struct foo{
int* i;
foo(): i(new int(42)){}
foo(const foo&) = delete;
foo(foo&&) = default;
~foo(){
std::cout << "destructor: i" << std::endl;
delete(i);
}
};
int main()
{
foo f;
auto sp_f = std::make_shared<foo>(std::move(f));
}
This is bad because it seems that the destructor of f will be called once it moves into the shared_ptr. The shared_ptr will have a deleted pointer and will delete it after it goes out of scope, which means the pointer will be deleted two times.
How do I avoid this problem?
You need to define the move constructor to prevent deletion from the moved-from object:
foo(foo&& f): i(f.i) {
f.i = nullptr;
}
Now when to destructor of the old object is run, it won't delete the i, since deleting a null pointer is a no-op.
You should also define a move assignment operator and delete the copy assignment operator too.
The rule of three is really the rule of five now. If you have a class that can be moved from, you should define the move semantics yourself (plus the copy, destructor, etc).
As to how to do that, to quote cppreference's page on std::move, "... objects that have been moved from are placed in a valid but unspecified state." The unspecified state is typically what the object would look like if it had been default initialized, or what would happen if the objects had swap called on them.
A straightforward way is, as #zenith has answered, is to have the move constructor (or assignment operator) set the original pointer to nullptr. This way the data isn't freed, and the original object is still in a valid state.
Another common idiom is, as mentioned, to use swap. If a class needs its own copy and move semantics, a swap method would be handy as well. The move constructor would delegate initialization to the default constructor, and then call the swap method. In a move assignment operator, just call swap. The object being moved into will get the resources, and the other object's destructor will free the original ones.
It would usually look like this:
struct Foo
{
void* resource; //managed resource
Foo() : resource(nullptr) {} //default construct with NULL resource
Foo(Foo&& rhs) : Foo() //set to default value initially
{
this->swap(rhs); //now this has ownership, rhs has NULL
}
~Foo()
{
delete resource;
}
Foo& operator= (Foo&& rhs)
{
this->swap(rhs); //this has ownership, rhs has previous resource
}
void swap(Foo& rhs) //basic swap operation
{
std::swap(resource, rhs.resource); //thanks #M.M
}
};
Related
This is an educational question, I am interested in what happens behind the scenes when I do:
SomeClass x(arg1, arg2, arg3); // An instance of SomeClass is constructed.
x = SomeClass(arg4, arg5, arg6); // Intent is to create a new instance.
SomeClass does not have operator= implemented.
Does the space allocated to x simply get overwritten as if it was newly allocated memory or what exactly happens? And when is it a good idea?
This can best be explained with the help of a small example:
Live on Coliru
struct A {
A(int a) { cout << "A::ctor\n"; } //ctor
A(const A& a) { cout << "A::copy\n"; } //copy ctor
A& operator=(const A& a) { cout << "A::operator=\n"; } //copy assign
};
int main()
{
A a(2); //calls constructor
a = A(10); //calls constructor first, then copy assignment
}
Output:
A::ctor
A::ctor
A::operator
The above is pretty self explanatory. For the first, only the constructor gets called. For the second, first the constructor is called and then copy assignment.
SomeClass does not have operator= implemented.
That doesn't matter because the compiler can generate one for you. If you explicitly delete it, then the above code will not compile. However, if you have a move constructor defined then that will be used:
(I highly recommend you read The rule of three/five/zero and understand it. It is among the top 5 things in C++ that you should know.)
A& operator=(const A& a) = delete; //copy assign deleted
A& operator=(A&& other) { cout << "move assigned\n"; } //move assign available
Now you maybe wondering what will happen if both copy and move assign are available. Lets see:
A a(2); //ctor
a = A(10); //ctor + move assign
A b(3); //ctor
b = a; // copy assign only
a = std::move(b); // move assign
For a = A(10) move assign is invoked because A(10) is an rvalue of the same type as what is on the left hand side of the =.
For the last case a = std::move(b);, we explicitly cast b to an rvalue (yes that's what std::move() does). Since it's an rvalue now, move assignment is invoked.
Does the space allocated to x simply get overwritten as if it was newly allocated memory or what exactly happens?
First the temporary is created: A(10). Space will of course be allocated for it.
It's result is then assigned to a, so previous values in a get overwritten
destructor for the temporary will be called
And when is it a good idea?
It is a good idea when you need it, it depends on your usecase. Generally I would recommend that don't copy assign unnecessarily.
Second line is call of constructor followed by call to assignment operator. Assigment default to shallow copy of non-static members into existing storage.
If you defined something that prevented compiler to create default operator=, i.e. you defined move constructor or move assignment, no assignment is possible unless you declared your own (why it is so surprising?) If default shallow copy is fine, you can write following declaration:
SomeClass& operator(const SomeClass&) = default;
= default provides mechanism to declare "default" behavior of special functions.
Now there is move assignment and in such case one would be preferred if it declared in given context. But it won't be declared by compiler if user provided destructor or copy\move constructor\assignment operator.
SomeClass& operator(SomeClass&&) = default;
Difference between two assignments exists only for class-types where "move" semantics may include transfer of ownership. For trivial types and primitive types it's a simple copy.
Compiler allowed to elide some actions including creation of storage for temporary object, so resulting code may actually write new values directly into x storage, provided that such elision won't change program behavior.
I got the follwing block of code:
#include <vector>
#include <iostream>
struct TestStruct {
bool wasCreated;
TestStruct() {
std::cout << "Default Constructor" << std::endl;
wasCreated = false;
}
~TestStruct() {
if (wasCreated) {
DoImportantStuff();
}
}
void Create() {
wasCreated = true;
}
// delete all copy stuff
TestStruct(const TestStruct&) = delete;
TestStruct& operator=(const TestStruct&) = delete;
// implement only move assignment & ctor
TestStruct(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
}
TestStruct& operator=(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
return *this;
}
// very important stuff
void DoImportantStuff() {
std::cout << "Do Important Stuff" << std::endl;
}
};
int main() {
std::vector<TestStruct> testVector;
testVector.emplace_back(TestStruct());
testVector.emplace_back(TestStruct());
std::cin.get();
}
This code leads to the output:
Default Constructor
Do Important Stuff
Default Constructor
Do Important Stuff
Do Important Stuff
Basicly I wanted to write a class, which owns memory but allocates this memory only when I call Create(). To avoid memory leaks and to avoid deleting not allocated memory I introduced wasCreated which will be only true when i call Create(). Every TestStruct should be saved in one vector. So in implemented move assigment & ctor and deleted both copy assigment & ctor.
Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory. Why is so and how do get the vector to call the default constructor on memory allocation? Do I need my own allocator?
Your problem is that your move constructor is implemented incorrectly. It swaps wasCreated between the newly created object and the one being moved from, but the variable in the newly created object has not been initialized yet (a default-constructed bool has an unknown value). So your temporary objects created with TestStruct() receive an uninitialized bool, which happens to be true in your case, hence the calls to DoImportantStuff() in their destructors.
So the move constructor should look something like this:
// implement only move assignment & ctor
TestStruct(TestStruct&& other) : wasCreated(other.wasCreated) {
other.wasCreated = false;
}
(You have moved ownership to the newly created object, the old one doesn't own anything anymore.)
Don't confuse the assignment operator with the constructor; they do different things. The assignment operator deals with two objects that are both already constructed; in the case of the constructor, the object being constructed is, well..., not constructed yet, so it doesn't have a valid state.
By the way, emplace_back() is pointless the way you're using it. Its purpose is to forward its arguments directly to the constructor of the object inside the vector. Since you have a default constructor (no arguments), the call should be:
testVector.emplace_back();
This will default-construct the TestStruct in place.
Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory.
A default-constructed vector has zero size, so there are no objects to construct.
If you want the vector to default-construct some objects, resize it.
I had a conversation with a friend of mine about object assignment and construction the other day, and he made a point that assignment a = b for objects is (semantically) equivalent to destroying a and then re-constructing it from b (at the same place).
But of course, nobody (I think) writes assignment operators like this:
class A {
A& operator=(const A& rhs) {
this->~A();
this->A(rhs);
return *this;
}
A& operator=(A&& rhs) {
this->~A();
this->A(std::move(rhs));
return *this;
}
// etc.
};
[Notice: I have no clue how to manually call constructors/destructors on existing objects (I never had to do that!), so their invocations may make no formal sense, but I guess you can see the idea.]
What are the problems with this approach? I imagine there has to be a main show-stopper, but the bigger the list, the better.
There is a misused contruction, here:
class A {
A& operator=(const A& rhs) {
if(&a==this) return *this;
this->~A();
new(this) A(rhs);
return *this;
}
A& operator=(A&& rhs) {
if(&a==this) return *this;
this->~A();
new(this) A(std::move(rhs));
return *this;
}
// etc.
};
This is correct respect to the inplace ctor/dtor semantics, and thsi is what std::allocator does to destroy and construct elements in a buffer, so that must be correct, right?
Well... not properly: it all is about what A in fact contains and what the A ctor actually does.
If A just contains basic types and does not own resources that's fine, it works. It's just not idiomatic, but correct.
If A contains some other resources, that need to be acquired, managed and released well... you may be in trouble. And you also are if A is polymorphic (if ~A is virtual you destroy the entire object, but then you reconstruct just the A subobject).
The problem is that a constructor that acquires resources may fail, and an object that fails in construction and throws must not be destroyed since it has been never "constructed".
But if you are "assigning", you are not "creating", and if the in-place ctor fails, your object will exist (because it pre-exist in its own scope), but is in a state that cannot be managed by a further destruction: think to
{
A a,b;
a = b;
}
At the } b and a will be destroyed but if A(const A&) failed in a=b, and a throw is made in A::A, a is not existing, but will be improperly destroyed at the } that throw will immediately jump to.
A more idiomatic way is to have
class A
{
void swap(A& s) noexcept
{ /* exchanging resources between existing objects should never fail: you just swap pointers */ }
public:
A() noexcept { /* creates an object in a "null" recognizable state */ }
A(const A& s) { /* creates a copy: may fail! */ }
A(A&& s) noexcept { /*make it as null and... */ swap(s); } // if `s` is temporary will caryy old resource deletionon, and we keep it's own resource going
A& operator=(A s) noexcept { swap(s); return *this; }
~A() { /* handle resource deletion, if any */ }
};
Now,
a=b
will create a b copy as the s parameter in operator= (by means of A::A(const A&)).
If this fails, s will not exist and a and b are still valid (with their own old values), hence at scope exiting will be destroyed as normally.
If the copy succeed, the copyed resources and the actual a's will be exchanged, and when s dies at the } the old-a resources will be freed.
By converse
a = std::move(b)
Will make b as-temporary, the s parameter constructed via A(A&&), so b will swap with s (and becomes null) than s will swap with a. At the end, s will destroy old a resources, a will receive old b's and b will be in null state (so it can die peacefully when its scope ends)
The problem of "making A as null" must be implemented in both A() and A(A&&).
This may be by means of an helper member (an init, just like a swap) or by specifying member initializers, or by defining default initialization values for members (once for all)
First of all, calling the destructor manually is required only if the object was constructed using an overloaded operator new() with some expections like using the std::nothrow overloads.
And what you got to understand is the difference between copy construction and assignment operator: copy constructor is called when a new object is created from an existing object, as a copy of the existing object. And assignment operator is called when an already initialized object is assigned a new value from another existing object.
To sum up, example of assignment operator you've provided doesn't make sense - it got to have different semantics.
If you have further questions, leave a comment.
First it is not legal to call a copy constructor directly (at least in C++ compliant compilers.. VS2012 allows that) so the following isn't allowed:
// assignment operator
A& operator=(const A& rhs) {
this->~A();
this->A::A(rhs); <--- Invalid use
at that point you can either rely on compiler optimizations (see copy elision and RVO) or allocate it on the heap.
Many issues can arise if you try to do the above:
1) You might have exceptions thrown in the expression for the copy constructor
In this case you will have
// assignment operator
A& operator=(const A& rhs) {
cout << "copy assignment called" << endl;
this->~A();
A newObj(rhs); // Can throw and A is in invalid state!
return newObj;
}
To make it safe you should use the copy-and-swap idiom:
set& set::operator=(set const& source)
{
/* You actually don't need this. But if creating a copy is expensive then feel free */
if (&source == this)
return;
/*
* This line is invoking the copy constructor.
* You are copying 'source' into a temporary object not the current one.
* But the use of the swap() immediately after the copy makes it logically
* equivalent.
*/
set tmp(source);
this->swap(tmp);
return *this;
}
void swap(set& dst) throw ()
{
// swap member of this with members of dst
}
2) You might have problems with dynamically allocated memory
In case two instances of A shared a pointer, you might have a dangling pointer before being able to release it
a = a; // easiest case
...
// assignment operator
A& operator=(const A& rhs) {
this->~A(); <-- Freeing dynamically allocated memory
this->A::A(rhs); <--- Getting a pointer to nowhere
3) As Emilio noted, if the class is polymorphic you're not going to be able to re-instantiate that subclass (unless you trick it somehow with a CRTP-like technique)
4) Finally assignment and copy construction are two different operations. If A contains resources which are expensive to re-acquire, you might find yourself in a lot of troubles.
I want to redirect my copy operator to my copy constructor. Where in the latter I implement the proper logic for copying/contructing a new class based on the old avaialble class.
However, how is the proper way to do this? I "think" this one is maybe leaking memory, but I don't know how to do it without passing a pointer:
MyClass& MyClass::operator=(const MyClass& a) {
MyClass* b = new MyClass(a);
return *b;
}
Is this OK? If is not, what would be the proper way? Should I change the body of the method or the prototype?
Thank you.
No, an operator= should set the current object attributes to be the same as the object assigned. Your method assigns a new object on the heap, returns it as a reference (essentially leaking it) and leaves the object the operator was called on completely unchanged.
You should implement a method called, for example, CopyFrom(), which assigns all the object's attributes to match those of the passed in object (deep copying any heap allocated pointers whose lifetime is managed by MyClass) and then call THAT from both your copy constructor and your operator=.
class MyClass
{
public:
MyClass( const MyClass& in )
{
CopyFrom( in );
}
MyClass& operator=( const MyClass& in )
{
CopyFrom( in );
return *this;
}
private:
void CopyFrom( const MyClass& in )
{
... copies in's attributes into self.
}
};
As a rule, a copy assignment operator should never create a copy. Rather, it should copy data into the existing object that it's called on (the left-hand side of the assignment). For example:
class MyClass
{
public:
MyClass & operator = (const MyClass & RHS)
{
// Copy data from RHS into 'this'
m_value = RHS.m_value;
return *this;
}
private:
int m_value;
};
In this case, defining your own copy constructor isn't necessary because the default (compiler-provided) one would work fine. It's just an illustration though.
Unfortunately you can't invoke the copy constructor on the existing object. The copy-swap pattern is an alternative, but it can be less efficient.
Unless you're storing pointers inside of MyClass, the correct copy assignment operator is the default-generated one. If, however you need to implement one, you can write it in terms of your copy-constructor via the copy-swap idiom:
MyClass& MyClass::operator = (MyClass const& a) {
MyClass temp(a); // Call the copy constructor
using std::swap;
swap(temp, *this);
return *this;
}
The reason for the using std::swap is to enable argument-dependent lookup. If you define your own swap function for MyClass, it will be called. Else std::swap will be used as a fallback. (EDIT: You do in fact need to implement a custom swap in this case, or else you will get infinite recursion. std::swap will use the assignment operator, which will call std::swap, which will call the...)
The reason that this idiom is well-liked is because std::swap is a no-throw function. If your copy-constructor were to throw an exception, then your object you're assigning to is still in a valid state.
The "proper way" is to implement the assignment operator like an assignment operator: modify the contents of the object on which the operator is being called and return a reference to it.
Your current implementation will result in a memory leak, AND doesn't do any assignment (which is the main point of the assignment operator).
If you only want to write the assignment code once, and your class doesn't allocate memory in the constructor, you could do this:
MyClass::MyClass(const MyClass& a) {
*this = a;
}
MyClass& MyClass::operator=(const MyClass& a) {
if (&a == this)
return *this;
// Do assignment
return *this;
}
But I wouldn't recommend it.
Your code is totally wrong (sorry)! The assignment operator does
not assign anything, but allocates a pointer to a MyClass object,
creating a memory leak. My advice: avoid pointers or use some
smart pointer (shared_ptr, unique_ptr), but that is just a side note.
Maybe this is helpful:
#include <iostream>
#include <limits>
class X
{
public:
X(std::size_t n)
: m_size(n), m_data(new int[n])
{
std::cout << "Construct" << std::endl;
}
~X()
{
std::cout << "Destruct" << std::endl;
delete [] m_data;
}
// Exception safe assignment.
// Note: I am passing by value to enable copy elision and
// move semantics.
X& operator = (X x) {
std::cout << "Assign" << std::endl;
x.swap(*this);
return *this;
}
void swap(X& x) {
std::swap(m_size, x.m_size);
std::swap(m_data, x.m_data);
}
std::size_t size() const { return m_size; }
private:
std::size_t m_size;
int* m_data;
};
int main()
{
X x(1);
try {
x = X(2);
// To provoke an exception:
std::size_t n = std::numeric_limits<std::size_t>::max();
x = X(n);
}
catch(...) {
std::cout << "Exception" << std::endl;
}
std::cout << "Size: " << x.size() << std::endl;
return 0;
}
If you absolutely want to implement the assignment operator by copy constructor, use the following:
MyClass& MyClass::operator=(const MyClass& o)
{
this->~MyClass(); // destroy current object
new(this) MyClass(o); // use the copy constructor
return *this;
}
I cannot think of any situation in which this would be the best thing to do (other answers describe ways of implementation that are better in some situations).
Maybe (just trying to make things up here) if MyClass contains hundreds of int/float fields, and several dynamically-allocated pointers?
Duplicating them in constructor and assignment operator is too tedious and error-prone
Having a copying function that both constructor and assignment operator call - not ideal, because pointers have to be set to NULL first
The code above - will work with no additional effort!
However, having bare (non-smart) pointers in your class is discouraged. If you have such a class, then you have far worse problems than non-working assignment operator - you have to refactor first, and the problem will go away, together with all other bugs.
In C++03 it is impossible to return an object of a class having a private non-defined copy constructor by value:
struct A { A(int x) { ... } private: A(A const&); };
A f() {
return A(10); // error!
return 10; // error too!
}
I was wondering, was this restriction lifted in C++11, making it possible to write functions having a class type return type for classes without constructors used for copy or move? I remember it could be useful to allow callers of a function use the newly returned object, but that they are not able to copy the value and store it somewhere.
Here is how it can work
A f() {
return { 10 };
}
This works even though A has no working copy or move constructor and no other constructor that could copy or move an A!
To make use of this feature of C++11, the constructor (taking int in this case) has to be non-explicit though.
The restriction has not been lifted. As per the access specifier, there is a note in §12.8/32 that explains:
two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.
As of the deleted copy/move constructors §8.4.3/2 states that
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]
Not sure about this particular case, but my understanding of the quote is that, if after the overload resolution in §12.8/32 the deleted copy/move constructor is selected, even if the operation is elided, that could constitute a reference to the function, and the program would be ill formed.
The above code is still ill-formed in C++11. But you could add a public move constructor to A and then it would be legal:
struct A
{
A(int x) {}
A(A&&);
private:
A(A const&);
};
A f() {
return A(10); // Ok!
}
I was wondering, was this restriction lifted in C++11?
How could it be? By returning something by value, you are by definition copying (or moving) it. And while C++ can allow that copy/move to be elided in certain circumstances, it's still copying (or moving) by the specification.
I remember it could be useful to allow callers of a function use the returned object, but that they are not able to copy the value and store it somewhere.
Yes. You get rid of the copy constructor/assignment, but allow the value to be moved. std::unique_ptr does this.
You can return a unique_ptr by value. But in doing so, you are returning an "prvalue": a temporary that is being destroyed. Therefore, if you have a function g as such:
std::unique_ptr<SomeType> g() {...}
You can do this:
std::unique_ptr<SomeType> value = g();
But not this:
std::unique_ptr<SomeType> value1 = g();
std::unique_ptr<SomeType> value2 = g();
value1 = value 2;
But this is possible:
std::unique_ptr<SomeType> value = g();
value = g();
The second line invokes the move assignment operator on value. It will delete the old pointer and move the new pointer into it, leaving the old value empty.
In this way, you can ensure that the contents of any unique_ptr is only ever stored in one place. You can't stop them from referencing it in multiple places (via pointers to unique_ptr or whatever), but there will be at most one location in memory where the actual pointer is stored.
Removing both the copy and move constructors creates an immobile object. Where it is created is where it's values stay, forever. Movement allows you to have unique ownership, but without being immobile.
You could probably hack together a proxy to do the trick if you really wanted, and have a converting constructor that copies the value stored within the proxy.
Something along the lines of:
template<typename T>
struct ReturnProxy {
//This could be made private, provided appropriate frienship is granted
ReturnProxy(T* p_) : p(p_) { }
ReturnProxy(ReturnProxy&&) = default;
private:
//don't want these Proxies sticking around...
ReturnProxy(const ReturnProxy&) = delete;
void operator =(const ReturnProxy&) = delete;
void operator =(ReturnProxy&&) = delete;
struct SUPER_FRIENDS { typedef T GO; };
friend struct SUPER_FRIENDS::GO;
unique_ptr<T> p;
};
struct Object {
Object() : data(0) { }
//Pseudo-copy constructor
Object(ReturnProxy<Object>&& proxy)
: data(proxy.p ? proxy.p->data : throw "Don't get sneaky with me \\glare")
{
//steals `proxy.p` so that there isn't a second copy of this object floating around
//shouldn't be necessary, but some men just want to watch the world burn.
unique_ptr<Object> thief(std::move(proxy.p));
}
private:
int data;
Object(const Object&) = delete;
void operator =(const Object&) = delete;
};
ReturnProxy<Object> func() {
return ReturnProxy(new Object);
}
int main() {
Object o(func());
}
You could probably do the same in 03, though, using auto_ptrs. And it obviously doesn't prevent storage of the resultant Object, although it does limit you to one copy per instance.