Is the address of a temporary object always the same as the address of the object it will be assigned to in C++?

106 Views Asked by At

In C++, suppose I have a C++ class called A, and inside it, I define a variable A* ptr;. In the constructor, there is an instruction ptr = this. Now, let's consider the following assignment initialization: A a = A(). My main question is whether a.ptr == &a is always true.

My primary concern is related to this assignment, which first creates a temporary object and then uses either the move constructor (possibly the copy constructor, I'm not entirely sure). I want to understand if the value of the ptr member in the temporary object is always the same as the address of the object it will be assigned to (i.e., whether the address of the temporary object is always the same as the address of a).

I have conducted experiments that seem to confirm this behavior, but I would like to know if this feature is guaranteed by the C++ standard.

3

There are 3 best solutions below

0
chi On BEST ANSWER

Assignment happens when you have already constructed two objects and you want to overwrite one with the value of the other. If an object is being constructed right now, that's called initialization, and no assignment takes place to that object.

A a;            // initialization
A b(32);        // initialization
A c = b;        // initialization
b = c;          // assignment
A d = A();      // initialization
A e{42};        // initialization
A *p = nullptr; // initialization (of a pointer)
p = new A();    // assignment of p, initialization of the new A object
*p = d;         // assignment of the A object

In your case the line A a = A(); performs initialization since a is being constructed right now. Since C++17, the initialization is performed in-place whenever the expression is a prvalue, like your A(). No copy is being performed here. The temporary object created by A() is never materialized in memory elsewhere and then copied, it's directly created in the right spot.

Effectively, you can pretend that no temporary object exists in this case. You can equivalently write A a; and obtain the same effect.

13
deribaucourt On

To sum up your question, we have the following:

class A {
    A() {
        ptr = this;
    }
    A* ptr;
}

int main() {
    A a = A();
}

As you stated, the A() statement produces a temporary object. The = operator will call the copy constructor. This does a shallow copy which means pointers are copied but not the pointees. In that case, this produces undefined behavior. It happens that your compiler is smart and directly reuses the temporary object, but it is not guaranteed by the language to my knowledge. When managing pointers, your class should follow the rule of three/five/zero.

In your specific case, I suggest properly specifying the copy constructor to update ptr to the new this address. Although I suppose you are asking this question within a broader program with child objects so it may not be as trivial to implement in your case.

A(const A& other) {
    ptr = this;
}

Following the rule, you should define or delete all related operators (move, constructors, destructor) simlarly.

Edit: Copy elision is guaranteed if using C++17 or above. See comment by 463035818-is-not-a-number . So your original code is safe with that version and up.

0
stefaanv On

Next code shows the temp object, a named object and a copy of a temp object as a function parameter (pass by const reference). Both the temp object as the named object show the same addresses, but the copied temp object shows the new address in ptr, but the old address of the named object.

struct A
{
  A* a;
  A() : a(this) {}
};

void fnc(const A& a)
{
  std::cout << "a.ptr " << a.a << " =?= &a " << &a << "\n";
}

int main()
{
  fnc(A());
  A a;
  fnc(a);
  a = A();
  fnc(a);
}

possible result

a.ptr 000000743053F7D8 =?= &a 000000743053F7D8
a.ptr 000000743053F6F8 =?= &a 000000743053F6F8
a.ptr 000000743053F7F8 =?= &a 000000743053F6F8