user2953119
user2953119

Reputation:

Undefined behavior caused by not proper memory reusing

The standard cite the following example (3.8/7 N3797):

struct C 
{
    int i;
    void f();
    const C& operator=( const C& );
};

const C& C::operator=( const C& other) 
{
    if ( this != &other ) 
    {
        this->~C(); // lifetime of *this ends
        new (this) C(other); // new object of type C created
        f(); // well-defined
    }
return *this;
}

C c1;
C c2;
c1 = c2; // well-defined
c1.f(); // well-defined; c1 refers to a new object of type C

Is there UB if we implement operator= as follows:

const C& C::operator=( const C& other) 
{
    if ( this != &other ) 
    {                        // Note that there is no more explcicitly destructor call,
                             // since at the time of memory reusing the lifetime of 
                             // this is still going on
        new (this) C(other); // new object of type C created
        f(); // well-defined
    }
return *this;
}

Relevant quote is:

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object

There is no rule for: "Creating a new object at the storage location than an object occupies". Meanwhile, we have a suitable rule for a const object. And it is clear:

Section 3.8/9:

Creating a new object at the storage location that a const object with static, thread, or automatic storage duration occupies or, at the storage location that such a const object used to occupy before its lifetime ended results in undefined behavior.

Upvotes: 1

Views: 72

Answers (1)

Igor Tandetnik
Igor Tandetnik

Reputation: 52471

The relevant rule is this:

3.8/4 A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.

Your example, as written, is legal because C has a trivial destructor.

Upvotes: 5

Related Questions