I have a class called Stack. I've implemented the copy constructor but for the copy assignment constructor I just have it call the copy constructor since the logic is the same. But for some reason it just returns a default constructed object. I don't understand why.
The copy constructor:
Stack::Stack( const Stack& s )
{
if ( s.Empty() )
{
this->entry = nullptr;
}
else
{
this->entry = new Entry();
Entry* i = this->entry;
for ( Entry* p = s.entry; p != nullptr; p = p->next )
{
i->number = p->number;
i->next = p->next == nullptr ? nullptr : new Entry();
i = i->next;
}
}
}
The copy assignment constructor:
Stack& Stack::operator=( const Stack& s )
{
return Stack( s );
}
The calling code:
Stack s;
s.Push( 5 );
s.Push( 3 );
Stack s2;
s2 = s; //s2 just ends up defaulted constructed instead of copied from s
If I replace the lines:
Stack s2;
s2 = s;
with:
Stack s2(s);
everything works just fine. What am I doing wrong here?
EDIT --
So the lesson here is to implement the assignment ctor and leverage that in the copy ctor, not the other way around as I had done.
The behaviour of your assignment operator is undefined.
You are returning a dangling reference .
The idiomatic way of writing the assignment operator is std::move
the instance of the object passed ( s
in your case, which you should pass by value) to self, and return *this
as a reference.
Your assignment operator is incorrect. It is returning a reference to a temporary object. It should return *this
instead:
Stack& Stack::operator=( const Stack& s )
{
// copy s to members
return *this;
}
If you want to avoid implementing things twice its usually easier to implement the assignment operator and use that in the copy constructor:
Stack::Stack( const Stack& s )
:Stack()
{
*this = s;
}
Stack& Stack::operator=( const Stack& s )
{
if (&s == this) return *this;
// TODO: free current members?
if ( s.Empty() )
{
this->entry = nullptr;
}
else
{
this->entry = new Entry();
Entry* i = this->entry;
for ( Entry* p = s.entry; p != nullptr; p = p->next )
{
i->number = p->number;
i->next = p->next == nullptr ? nullptr : new Entry();
i = i->next;
}
}
return *this;
}
When you do
Stack& Stack::operator=( const Stack& s )
{
return Stack( s );
}
Stack(s)
creates an object with a scope limited to the current function. You then return a reference to this local object.
So, when doing x = y
, x
is not modified to become a copy of y
and a reference to an object that is out of scope is returned, then discarded.
The job of the Stack& Stack::operator=( const Stack& s )
is not to return a copy. Its job is to modify x
(called this
) so that it becomes equal to y
(called s
).
So, the proper way would look something like:
Stack& Stack::operator=( const Stack& s )
{
this->entry = new Entry();
// then all the code to make `this` equal to `s`
}
Since you have a working copy constructor and working destructor for Stack
, you can simply use copy / swap to implement the assignment operator:
Stack& Stack::operator=( const Stack& s )
{
if ( this != &s)
{
Stack temp(s);
std::swap(temp.entry, entry);
}
return *this;
}
If you have other member variables, you will need to swap those also.
This works by creating a temporary, and simply swapping out the members of the current object ( this
) with the copy's members. Then the copy dies off with the old data.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.