c++ copy assignment : why it is not applicable to use it dealing with uninitiated object?

move constructor in c++ geeksforgeeks
move assignment operator
copy assignment operator(c)
when is move constructor called
move constructor c++
c++ copy constructor
assignment operator c++ overload
c default move constructor

I am reading BJARNE STROUSTRUP's great book : Programming : Principles and Practices using C++ programming. I am reading the part in which he tries to show how to design a vector. However, one sentence caught me. (I can only tell you the location of this sentence in the whole book if you are also reading this book, which is unlikely, so I don't locate it here.)

"We move an element to the new space by constructing a copy in uninitialized space and then destroying the original. We can’t use assignment because for types such as string, assignment assumes that the target area has been initialized."

To help you get the context, I provide some codes here:

template<typename T, typename A = allocator<T>> class my_vector {
          A alloc;             // use allocate to handle memory for elements
          // . . .
private : 
    T* elem;
    int sz;//short for size
    int space;//actually means capacity here.
};

He is trying to show how to implement reserve(). The implementation is here:

template<typename T, typename A>
void my_vector<T,A>::reserve(int newalloc)
{
          if (newalloc<=space) return;               // never decrease allocation
          T* p = alloc.allocate(newalloc);          // allocate new space
     /***/for (int i=0; i<sz; ++i) alloc.construct(&p[i],elem[i]);// copy!!! he means we can't use copy assignment operator here!
          for (int i=0; i<sz; ++i) alloc.destroy(&elem[i]);                 // destroy
          alloc.deallocate(elem,space);             // deallocate old space
          elem = p;
          space = newalloc;
}

He means that we can only copy construct the elem using alloc.construct() rather than using simple copy assignment such as p[i] = elem[i]. And the reason he gives is what I quoted above.

Assuming copy assignment is defined for the generic type T (maybe using Concepts), why copy assignment can't be used here still? He says

"such as string, assignment assumes that the target area has been initialized".

However, I don't get it anyway. Can you help me to understand his gist? I think copy assignment works out fine even target is uninitiated, after all, the target is the one to be initiated.

Thanks!

Lets say you have a class like

struct Foo
{
    int * data;
    int size
    Foo() : data(nullptr), size(0) {}
    Foo(const Foo& f) : data(new int[f.size]), size(f.size) 
    { 
        std::copy(f.data, f.data + f.size, data);
    }
    Foo& operator=(const Foo& f)
    {
        if (&f == this)
            return *this;
        else
        {
            if (size < f.size)
                //allocate new space
            // copy
        }
    }
};

Now, if we replace

for (int i=0; i<sz; ++i) alloc.construct(&p[i],elem[i]);

with

for (int i=0; i<sz; ++i) p[i] = elem[i];

This isn't going to work. p[i] refers to a Foo that was never constructed. That means none if its members have been set which means when we do if (size < f.size) we are accessing an uninitialized variable and that is undefined behavior.

This is why we make a copy (or move in C++11 and above). It guarantees the object is constructed and that the "right thing" happens.

Assignment operator (C++), Copying from ancestor to descendant objects, which could leave descendant's fields uninitialized, is not permitted. See also[edit]. Operator overloading · Rule of​  Dealing with the “depends on non-NOTIFYable properties” warning needs to be set on a per-object basis, it is not applicable to use a QML assignment or

Sometimes copy assignment should assume that the target is initialized. For example, vector. When assigning a vector to another vector, resources in assigned vector should be delete, and that inevitably assume that the target is initialized because we have to reference the member pointer.

15.3, By default, C++ will provide a copy constructor and copy assignment operator if one So classes that deal with dynamic memory should override these 4) The temporary object is assigned to mainres by copy assignment. the move flavors of these functions use non-const r-value reference parameters. If not NULL and the CDatabase object's Open member function has not been called to connect it to the data source, the recordset attempts to open it for you during its own Open call. If you pass NULL, a CDatabase object is constructed and connected for you using the data source information you specified when you derived your recordset class with

Vector is too advanced. I'm pretty sure a few hundred pages precede this example. So, If you have read the book carefully, you must have noticed the difference between assignment and initialization(more formally construction). Construction is like building a garage, whereas assignment is like parking a car inside the garage. How are you supposed to put a car in an unbuilt garage?

T* p = alloc.allocate(newalloc);

That just allocates the space, no object has been constructed yet(There is no garage). Thus assignment is not applicable(wanna park your car at the edge of a hazard?). So the next step is to build the objects and the best choice is copy/move construction. It is possible to default construct(build empty garages) an then assign to the objects(park the cars),but it is more efficient to copy/move construct and in terms of template library development, less demanding too. Remember that allocators behave differently than new in that the latter automatically constructs the object(s) immediately after allocation while the former separates the 2 phases.

Inconsistent definition of copy constructor and assignment ('Rule of , Description: Classes that have an explicit copy constructor or copy assignment operator may behave inconsistently if they do not have both. and since they deal with similar concerns it is likely that if the default The object initialization (​that is, Class c1 = c2 ) may behave C( const C& copyFrom) {. Fourth, Try to use the C ++ STL whenever possible. It offers the best C ++ feature and implementation of trivial stuff almost bug free. So you do not have the hassle of dealing with trivial and non-trivial problem. I don't know If I have missed something, maybe someone else may point it out. If you have any question, just ask.

C++ Core Guidelines: Rules for Copy and Move, C.60: Make copy assignment non- virtual , take the parameter by const& , and C.64 states the moved-from object should be in a valid state. If you want to use the default value of the underlying value type in place of null, use the Nullable<T>.GetValueOrDefault() method. You also can explicitly cast a nullable value type to a non-nullable type, as the following example shows:

Top 20 C pointer mistakes and how to fix them, Always initialize pointers to a valid value. Deceptively simple – do not assign pointers to uninitialized variables. Mistake # 11 : Creating garbage objects using C pointers Given two pointers p and q, the assignment p = q does not copy the block of memory pointed to by q into a block of memory  But if the object already exist in the memory it does not create a new Object rather it assigns the same old object to the new instance, that means even though we have two string instances above(str1 and str2) compiler only created on string object (having the value “Welcome”) and assigned the same to both the instances.

Copy Constructor, A C++ compiler will create a copy constructor and assignment operator for your class Also, the new C++11 specification lets you disable these default functions made the object be non-copyable by declaring a private copy constructor and objects begin life uninitialized and it is possible to accidentally attempt to use a​  The problem is only when you read a variable that has not been written yet. Depending on the compiler and/or on the kind of variable, initialization is performed at application startup. Or not. It is common usage to not rely on automatic initialization.

Comments
  • The book says that std::string's assignment operator assumes that the target is initialized. Don't you believe it, or did you misunderstand it? (Assignment is when you give a new value to a thing that already exists; it does not initialize anything.)
  • There are many undefined behaviors even in the construct-then-copy version according to the current standard. So maybe this question can be only answered in a "practical" way. You may get a standard-confirmed answer when this paper is accepted.
  • @molbdnilo I get your point. You mean that constructors are the one to do the initialization thing, and assignment are used for assigning values to already constructed objects. But why can't we use one implementation of copy assignment that also does the "initialization", which means no longer assume that target is initiated? Maybe it's because of performance. But are there any other "inevitable" reasons so that we must assume target is initiated when implementing copy assignment? Or is it just a usage philosophy?
  • Try to implement assignment for a class that does any kind of resource management (like strings of vectors dynamic storage) and that doesn't require the target to be initialized. (Remember that you can't tell from looking at something whether it has been.)
  • Thanks! So that somewhat depends on the implementation of assign operator. To be more specific, whether the implementor assume the target is initiated or not. If implementor assume the target is not initiated when assign operator is called, that can be avoided. Sometimes assuming target is initiated can bring about some code optimization, just like the if statement in your code but sacrifice some "portability". So we comes to the debate of philosophy that whether we should assume target is initiated when implementing copy assignment, or move assignment.
  • BTW, is there any case that we must assume target is initiated when implementing copy assignment? I mean, some "inevitable" cases. That's should be more convincing.