If temporaries are implicitly non-modifiable, how does this work?

前端 未结 2 1064
隐瞒了意图╮
隐瞒了意图╮ 2020-11-30 08:23

I\'m told that, in C++03, temporaries are implicitly non-modifiable.

However, the following compiles for me on GCC 4.3.4 (in C++03 mode):

cout <&l         


        
相关标签:
2条回答
  • 2020-11-30 08:48

    I'm told that, in C++03, temporaries are implicitly non-modifiable.

    That is not correct. Temporaries are created, among other circumstances, by evaluating rvalues, and there are both non-const rvalues and const rvalues. The value category of an expression and the constness of the object it denotes are mostly orthogonal 1. Observe:

          std::string foo();
    const std::string bar();
    

    Given the above function declarations, the expression foo() is a non-const rvalue whose evaluation creates a non-const temporary, and bar() is a const rvalue that creates a const temporary.

    Note that you can call any member function on a non-const rvalue, allowing you to modify the object:

    foo().append(" was created by foo")   // okay, modifying a non-const temporary
    bar().append(" was created by bar")   // error, modifying a const temporary
    

    Since operator= is a member function, you can even assign to non-const rvalues:

    std::string("hello") = "world";
    

    This should be enough evidence to convince you that temporaries are not implicitly const.

    1: An exception are scalar rvalues such as 42. They are always non-const.

    0 讨论(0)
  • 2020-11-30 08:50

    First, there's a difference between "modifying a temporary" and "modifying an object through an rvalue". I'll consider the latter, since the former is not really useful to discuss [1].

    I found the following at 3.10/10 (3.10/5 in C++11):

    An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]

    So, rvalues are not const per-se but they are non-modifiable under all but some certain circumstances.

    However, that a member function call can modify an rvalue would seem to indicate to me that the vast majority of cases for modifying an object through an rvalue are satisfied.

    In particular, the assertion (in the original question I linked to) that (obj1+obj2).show() is not valid for non-const show() [ugh, why?!] was false.

    So, the answer is (changing the question wording slightly for the conclusion) that rvalues, as accessed through member functions, are not inherently non-modifiable.


    [1] - Notably, if you can obtain an lvalue to the temporary from the original rvalue, you can do whatever you like with it:

    #include <cstring>
    
    struct standard_layout {
        standard_layout();
        int i;
    };
    
    standard_layout* global;
    
    standard_layout::standard_layout()
    {
        global = this;
    }
    
    void modifying_an_object_through_lvalue(standard_layout&&)
    {
        // Modifying through an *lvalue* here!
        std::memset(global, 0, sizeof(standard_layout));
    }
    
    int main()
    {
        // we pass a temporary, but we only modify it through
        // an lvalue, which is fine
        modifying_an_object_through_lvalue(standard_layout{});
    }
    

    (Thanks to Luc Danton for the code!)

    0 讨论(0)
提交回复
热议问题