What is the common idiom(s) for resetting the moved object? - c++

In C++ move constructor is required to reset the moved object which to me seems to be a duplication of what the destructor does in most of the cases.
Is it correct that defining a reset-method and using it in both destructor and move-constructor is the best approach? Or maybe there are better ways?

Move constructors typically "steal" the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc.) rather than make copies of them, and leave the argument in some valid but otherwise indeterminate state. For some types, such as std::unique_ptr, the moved-from state is fully specified.
"Stolen" resources should not be released as this will usually lead to errors. For example, a move constructor which "steals" a pointer has to ensure that the destructor of the moved-from object won't delete the pointer. Otherwise, there will be a double-free. A common way of implementing this is to reset the moved-from pointer to nullptr.
Here is an example:
struct Pointer {
int *ptr;
// obtain a ptr resource which we will manage
Pointer(int* ptr) : ptr{ptr} {}
// steal another object's ptr resource, assign it to nullptr
Pointer(Pointer &&moveOf) : ptr{moveOf.ptr} {
moveOf.ptr = nullptr;
}
// make sure that we don't delete a stolen ptr
~Pointer() {
if (ptr != nullptr) {
delete ptr;
}
}
};
Is it correct that defining a reset-method and using it in both destructor and move-constructor is the best approach? Or maybe there are better ways?
This depends on the resource which is managed, but typically the destructor and move-constructor do different things. The move constructor steals the resource, the destructor frees a resource if it hasn't been stolen.
In C++ move constructor is required to reset the moved object which to me seems to be a duplication of what the destructor does in most of the cases.
You are right that there often is duplication of work. This is because C++ does not have destructive move semantics, so the destructor still gets called separately, even when an object has been moved from. In the example I have shown, ~Pointer() still needs to get called, even after a move. This comes with the runtime cost of checking whether ptr == nullptr. An example of a language with destructive move semantics would be Rust.
Related Posts:
Why does C++ move semantics leave the source constructed?
How does Rust provide move semantics?
How to define a move constructor?

is required to reset the moved object which to me seems to be a duplication of what the destructor does in most of the cases.
It seems to me that you misunderstand what a destructor is used for in most cases.
The purpose of the "reset" (as you call it) in move is to set the state of the object so that it satisfies the internal pre-conditions of the destructor (more generally, any class invariant). If the constructor didn't do that, then the object couldn't be destroyed, which would be against conventions and good practices and would likely lead to mistakes.
In many cases, the destructor cannot possibly do this same "reset". For example, there is no way to distinguish an invalid pointer from a valid pointer. This is why the move constructor of a smart pointer resets the pointer to null.
Is it correct that defining a reset-method and using it in both destructor and move-constructor is the best approach?
It is unclear when this could be useful. Doesn't seem typical.

Related

Why doesn't moving an object leave it null?

A a5(move(a1));
While after the move the member vars of a1 are set to defaults, a1 itself is not set to null. You can't do a1 == nullptr... to check if a1 is useless...
I find this odd. Is there something I'm misunderstanding here? I would think that if a1 is moved, it becomes useless, this should be indicated by setting it to null somehow. No?
The thing is that by leaving a1 in a non null state, it still can be used. There is no compiler warning or error. There is no real indication that the object is in a messed up state. if a has two member vars, an int and a dynamically alloc object, the dyn alloc object will point to nullptr but the int will have a def value (of course only if implemented right...easy to mess up).
So after the move you can
int number = a1.getInt();
and get back a number not realizing that a1 has been reset. In C and C++ we're taught to set pointers to null (a.k.a nullptr or NULL) when its resource is pilfered to eliminate such confusion. With the introduction of moving which pilfers resources of an object, is there no built in mechanism or best practice to indicate the object has been pilfered and thus left "reset" to default construction state?
EDIT
Added sample move c'tor
A(A&& other) : num(other.num), s(other.s){
other.num = 0;
other.s = nullptr; //dyn alloc obj
}
Why doesn't moving an object leave it null?
Because if the object is not a pointer, then it does not, in general, have a "null state", so you can't "leave it null"; and if it is a pointer you don't make it null when you "move" from it.
Leaving a1 in a non null state, it still can be used. There is no compiler warning or error. There is no real indication that the object is in a messed up state...
It's not in a messed-up state, it's in a valid state. But perhaps it's not a bad idea for there to be warning when you use the post-move value of a moved-from object.
The result of a move operation is supposed to leave the object in a valid but unspecified state. Typically you would move if you are going to destroy the object, or assign new values to the object. You would not normally attempt to use an object after moving out of it.
The move-constructor for a1's type is responsible for performing the move and leaving the object in the state that you wish. If the default-generated move constructor does not behave as you would like then you can write your own move constructor for the object. For example you could set a pointer to null in this move constructor. Or you could set a flag which indicates the object is in a moved-from state.
In your question the behaviour you "wish for" is more like the behaviour of swapping with an empty object. Perhaps the following code would suit you better:
A a5{};
using std::swap;
swap(a5, a1);
Regarding the update which suggests other.s points to a "dyn alloc obj": you should avoid doing this because it means you have to waste time writing a copy-constructor, move-constructor, copy-assignment operator, move-assignment operator, and destructor.
You are the architect of your own demise here: by introducing this pointer to your class you create the exact problem with moving that you are complaining about.
Instead any owned resource should be managed by its own class. The standard library's std::unique_ptr suffices for many such use cases.

What is the right way to implement move semantics in a class that follows the pimpl design pattern?

What is the standard way to do it?
Let's have a class A that has a data member std::unique_ptr<Impl> m_impl.
For example, should class A's move assignment operator's contents look like this?
m_impl = std::move(other.m_impl);
Or this?
*m_impl = std::move(*other.m_impl);
The first case would be much more efficient than the second. But it would raise a few issues.
After moving, the m_impl data member of other is nullptr. Should the moved-from object throw exceptions when it's being used or just let the user run into runtime errors due to dereferencing a nullptr?
For thread-safe classes this would also mean that all m_impl usage needs to be synchronized. I am not sure if calling std::unique_ptr's move constructor/assignment operator is thread-safe or not.
The former. When you are using a unique_ptr, you are probably doing it because the object itself probably isn't copyable and/or movable in the first place. So moving the pointee is usually not an option.
After moving, the m_impl data member of other is nullptr.
That is correct moved-from std::unique_ptr. It needs to support destruction and reassignment and everything else is undefined and does not matter what it does (segfault in case of null pointer).
For thread-safe classes this would also mean that all m_impl usage needs to be synchronized.
Standard library is not thread-safe unless explicitly stated, only reentrant. If you object needs to be thread-safe, you have to ensure it yourself.
That said if a thread moves an object of which it is not a sole owner, it will cause problems for the other threads, because they will still try to access it at the old location.
You could lock the move operations against all operations on the object and define semantics of the operations on the moved-from object to return error in some way, but it sounds like big pain and seriously confusing to use.
Thread-safe objects should really be exception. You should aim for handing objects over between threads so that only one owns the object at any given time and to have all shared data immutable (except possible reference count, which can be done with reasonably performant std::atomic or std::shared_ptr, which is built on top of it).
If you really need a thread-safe object, it should either not be movable, or should behave like handle referring to it's internals by std::shared_ptr, which is thread-safe.
Let's see this with light from a different topic.
How do you swap pimpl class objects?
void swap(T& x, T& y) {
std::swap(x.m_impl, y.m_impl);
}
Right?
It only moves around the m_impl pointer. So, with move semantics, you should also only move the m_impl pointer!
m_impl = std::move(other.m_impl);
However, as an effect, users of your class should not dereference m_impl in a moved-from object. This is something move semantics introduces when you use it in your classes. It is up to the users of your class to prevent this from happening, just as your code should not do v[0] if v is a moved-from std::vector, etc.
A moved-from object is not supposed to be "alive" anymore (valid but unspecified) valid but unspecified:
Destruction allowed
Re-Assignment allowed
Other use disallowed
The first option, i.e. moving the member (i.e. ones on innards) and not the referencee, is preferable.

why is the destructor call after the std::move necessary?

In The C++ programming language Edition 4 there is an example of a vector implementation, see relevant code at the end of the message.
uninitialized_move() initializes new T objects into the new memory area by moving them from the old memory area. Then it calls the destructor on the original T object, the moved-from object. Why is the destructor call necessary in this case?
Here is my incomplete understanding: moving an object means that the ownership of the resources owned by the moved-from object are transferred to the moved-to object. The remainings in the moved-from object are some possible members of built-in types that do not need to be destroyed, they will be deallocated when the the vector_base b goes out of scope (inside reserve(), after the swap() call). All pointers in the moved-from object are to be put to nullptr or some mechanism is employed to drop ownership of moved-from object on those resources so that we are safe, then why call the destructor on a depleted object when the "vector_base b" destructor will anyway deallocate the memory after the swap is done?
I understand the need to explicitly call the destructor in the cases when it must be called because we have something to destruct (e.g. drop elements) but I fail to see its meaning after the std::move + deallocation of vector_base. I read some texts on the net and I'm seeing the destructor call of the moved-from object as an signal (to whom or what?) that the lifetime of the object is over.
Please clarify to me what meaningful work remains to be done by the destructor? Thank you!
The code snippet below is from here http://www.stroustrup.com/4th_printing3.html
template<typename T, typename A>
void vector<T,A>::reserve(size_type newalloc)
{
if (newalloc<=capacity()) return; // never decrease allocation
vector_base<T,A> b {vb.alloc,size(),newalloc-size()}; // get new space
uninitialized_move(vb.elem,vb.elem+size(),b.elem); // move elements
swap(vb,b); // install new base
} // implicitly release old space
template<typename In, typename Out>
Out uninitialized_move(In b, In e, Out oo)
{
using T = Value_type<Out>; // assume suitably defined type function (_tour4.iteratortraits_, _meta.type.traits_)
for (; b!=e; ++b,++oo) {
new(static_cast<void*>(&*oo)) T{move(*b)}; // move construct
b->~T(); // destroy
}
return oo;
}
Moving from an object just means that the moved-from object might donate its guts to live on in another live object shortly before it is [probably] going to die. Note, however, that just because an object donated its guts that the object isn't dead! In fact, it may be revived by another donating object and live on that object's guts.
Also, it is important to understand that move construction or move assignment can actually be copies! In fact, they will be copies if the type being moved happens to be a pre-C++11 type with a copy constructor or a copy assignment. Even if a class has a move constructor or a move assignment it may choose that it can't move its guts to the new object, e.g., because the allocators mismatch.
In any case, a moved from object may still have resources or need to record statistics or whatever. To get rid of the object it needs to be destroyed. Depending on the class's contracts it may even have a defined state after being moved from and could be put to new use without any further ado.
In his proposal to implement move semantics through rvalue references, Howard Hinant considered the push for Destructive Move too. But as he pointed in the same article, a move operation basically deals with to objects (source an destination) simultaneously in transition state - even in single threaded applications. The problem with destructive move is that either source, or destination will experience a state in where derived subpart of an object is constructed while base subpart is destroyed or uninitialized. This was not possible prior to move proposal, and is not acceptable yet. So the other choice left was to leave the moved from object in a valid empty state and let the destructor remove the valid empty state. For many practical purposes, destroying valid empty state is a noop; But it's not possible to be generalized for all cases. So, the moved from object is supposed to be either destructed, or assigned(move or copy) to.

Disallowing assignment and passing by value

From what I understand I'm able to "disable" copying and assigning to my objects by defining private copy constructor and assignment operator:
class MyClass
{
private:
MyClass(const MyClass& srcMyClass);
MyClass& operator=(const MyClass& srcMyClass);
}
But what's the usage of this?
Is it considered a bad practice?
I would appreciate if you could describe the situation, in which it would be reasonable / useful to "disable" assignment and copy constructor in this way.
It's useful when it doesn't make sense for your object to be copied. It is definitely not considered bad practice.
For instance, if you have a class that represents a network connection, it's not meaningful to copy that object. Another time you may want a class to be noncopyable is if you had a class representing one player in a multiplayer game. Both these classes represent things that can't be copied in the real world, or that don't make sense to copy (a person, a connection).
Also, if you are trying to implement a Singleton, it's standard procedure to make the objects non-copyable.
Generally speaking any class that manages a resource should be none-copyable or have specialized copy semantics. The converse is true as well: any class that is non-copyable or needs specialized copy semantics is managing a resource. "Manage a resource" in the C++ lingua in practice means responsible for some space in memory, or for a connection to a network or a database, or a handle to a file, or an undo transaction, and so on.
Resource management captures quite a lot of examples. These are responsibilities that take a prefix operation, a suffix operation and possibly some action in between. Memory management, for example, involves acquiring a handle to a memory address which we'll manage, perhaps mess around with that memory, and finally release the handle (because if you love something, let it be free).
template<typename T>
struct memory {
memory(T const& val = T()) : p(new T(val)) { }
~memory() { delete p }
T& operator*() const { return *p; }
private:
T* p;
};
// ...
{
memory<int> m0;
*m0 = 3;
std::cout << *m0 << '\n';
}
This memory class is almost correct: it automatically acquires the underlying memory space and automatically releases it, even if an exception propagates some time after it acquired its resource. But consider this scenario:
{
memory<double> m1(3.14);
memory<double> m2(m1); // m2.p == m1.p (do you hear the bomb ticking?)
}
Because we didn't provide specialized copy semantics for memory, the compiler provides its own copy constructor and copy assignment. These do the wrong thing: m2 = m1 means m2.p = m1.p, such that the two pointers point at the same address. It's wrong because when m2 goes out of scope it frees its resource like a good responsible object, and when m1 then goes out of scope it too frees its resource, that same resource m2 has already freed, completing a double-delete -- a notorious undefined behaviour scenario. Moreover, in C++ it's extremely easy to make copies of an object without even noticing: a function taking its parameter by value, returning its parameter by value, or taking its parameter by reference but then calling another function which itself takes (or returns) its parameter by value ... It's easier to just assume that things will try to get copied.
All this to say that when a class' raison d'ĂȘtre is managing a resource then you immediately should know that you need to handle copying. You should decide
you support copying, whereas you decide what copying means: safe sharing of the resource, performing a deep copy of the underlying resource so there is no sharing whatsoever, or combining the two approaches as in copy-on-write or lazy copy. Whatever path you choose you will need to provide a specialized copy constructor and a copy assignment operator.
or you don't support any sort of copying of the resource, in which case you disable the copy constructor and the copy assignment operator.
I'd go so far and say that resource management is the only case where you disable copying or provide specialized copy semantics. This is just another perspective on The Rule of Three.
It's a pretty common practice. There are are lots of examples where copying isn't appropriate.
Let's say your object represents an open server-side socket (i.e. an incoming network connection); what would be the semantics of making a copy of that object?
when you are allowed to create instance of object only after checking like in the case of singleton u need private constructors. when constructor is called the object instance will be called and then there is no point in checking if there is another instance already. so what we do is call a member function of class from main and inside that member function check if another instance is already in the memory. if not constructor is called. else aborted.
check singleton classes or other protected classes where data of object has to be kept secured and should not be allowed to copy.
also check this : Singleton Class in C++
When you are trying to implement a singleton pattern it's perfectly acceptable to use a private constructor as it's meant to be only instantiated inside itself and from nowhere else.
Once invoked, the constructor can't be revoked. So the constructor is invoked only after checking if the singleton condition satisfied.

C++ using scoped_ptr as a member variable

Just wanted opinions on a design question. If you have a C++ class than owns other objects, would you use smart pointers to achieve this?
class Example {
public:
// ...
private:
boost::scoped_ptr<Owned> data;
};
The 'Owned' object can't be stored by value because it may change through the lifetime of the object.
My view of it is that on the one side, you make it clear that the object is owned and ensure its deletion, but on the flipside, you could easily just have a regular pointer and delete it in the destructor. Is this overkill?
Follow up: Just wanted to say thanks for all your answers. Thanks for the heads-up about auto_ptr leaving the other object with a NULL pointer when the whole object is copied, I have used auto_ptr extensively but had not thought of that yet. I make basically all my classes boost::noncopyable unless I have a good reason, so there's nothing to worry about there. And thanks also for the information on memory leaks in exceptions, that's good to know too. I try not to write things which could cause exceptions in the constructor anyway - there are better ways of doing that - so that shouldn't be a problem.
I just had another question though. What I wanted when I asked this question was to know whether anyone actually did this, and you all seem to mention that it's a good idea theoretically, but no one's said they actually do it. Which surprises me! Certainly one object owning a pointer to another is not a new idea, I would have expected you all would have done it before at some point. What's going on?
scoped_ptr is very good for this purpose. But one has to understand its semantics. You can group smart pointers using two major properties:
Copyable: A smart pointer can be copied: The copy and the original share ownership.
Movable: A smart pointer can be moved: The move-result will have ownership, the original won't own anymore.
That's rather common terminology. For smart pointers, there is a specific terminology which better marks those properties:
Transfer of Ownership: A smart pointer is Movable
Share of Ownership: A smart pointer is copyable. If a smart pointer is already copyable, it's easy to support transfer-of-ownership semantic: That then is just an atomic copy & reset-of-original operation, restricting that to smart pointers of certain kinds (e.g only temporary smart pointers).
Let's group the available smart pointers, using (C)opyable, and (M)ovable, (N)either:
boost::scoped_ptr: N
std::auto_ptr: M
boost::shared_ptr: C
auto_ptr has one big problem, in that it realizes the Movable concept using a copy constructor. That is because When auto_ptr was accepted into C++, there wasn't yet a way to natively support move semantics using a move constructor, as opposed to the new C++ Standard. That is, you can do the following with auto_ptr, and it works:
auto_ptr<int> a(new int), b;
// oops, after this, a is reset. But a copy was desired!
// it does the copy&reset-of-original, but it's not restricted to only temporary
// auto_ptrs (so, not to ones that are returned from functions, for example).
b = a;
Anyway, as we see, in your case you won't be able to transfer the ownership to another object: Your object will in effect be non-copyable. And in the next C++ Standard, it will be non-movable if you stay with scoped_ptr.
For implementing your class with scoped_ptr, watch that you either have one of these two points satisfied:
Write an destructor (even if it's empty) in the .cpp file of your class, or
Make Owned a completely defines class.
Otherwise, when you would create an object of Example, the compiler would implicitly define a destructor for you, which would call scoped_ptr's destructor:
~Example() { ptr.~scoped_ptr<Owned>(); }
That would then make scoped_ptr call boost::checked_delete, which would complain about Owned being incomplete, in case you haven't done any of the above two points. If you have defined your own dtor in the .cpp file, the implicit call to the destructor of scoped_ptr would be made from the .cpp file, in which you could place the definition of your Owned class.
You have that same problem with auto_ptr, but you have one more problem: Providing auto_ptr with an incomplete type is undefined behavior currently (maybe it will be fixed for the next C++ version). So, when you use auto_ptr, you have to make Owned a complete type within your header file.
shared_ptr doesn't have that problem, because it uses a polymorphic deleter, which makes an indirect call to the delete. So the deleting function is not instantiated at the time the destructor is instantiated, but at the time the deleter is created in shared_ptr's constructor.
It's a good idea. It helps simplify your code, and ensure that when you do change the Owned object during the lifetime of the object, the previous one gets destroyed properly.
You have to remember that scoped_ptr is noncopyable, though, which makes your class noncopyable by default until/unless you add your own copy constructor, etc. (Of course, using the default copy constructor in the case of raw pointers would be a no-no too!)
If your class has more than one pointer field, then use of scoped_ptr actually improves exception safety in one case:
class C
{
Owned * o1;
Owned * o2;
public:
C() : o1(new Owned), o2(new Owned) {}
~C() { delete o1; delete o2;}
};
Now, imagine that during construction of a C the second "new Owned" throws an exception (out-of-memory, for example). o1 will be leaked, because C::~C() (the destructor) won't get called, because the object has not been completely constructed yet. The destructor of any completely constructed member field does get called though. So, using a scoped_ptr instead of a plain pointer will allow o1 to be properly destroyed.
It's not overkill at all, it's a good idea.
It does require your class clients to know about boost, though. This may or may not be an issue. For portability you could consider std::auto_ptr which does (in this case) the same job. As it's private, you don't have to worry about other people attempting to copy it.
Using the scoped_ptr is a good idea.
Keeping and manually destroying the pointer is not as simple as you think. Especially if there is more than one RAW pointer in your code. If exception safety and not leaking memory is a priority then you need a lot of extra code to get it correct.
For a start you have to make sure you correctly define all four default methods. This is because the compiler generated version of these methods are fine for normal objects (including smart pointers) but in the normal case will lead to problems with pointer handling (Look for the Shallow Copy Problem).
Default Constructor
Copy Constructor
Assignment Operator
Destructor
If you use the scoped_ptr then you don't need to worry about any of those.
Now if you have more than one RAW pointer in your class (or other parts of your constructor can throw) . You have to EXPLICITLY deal with exceptions during construction and destruction.
class MyClass
{
public:
MyClass();
MyClass(MyClass const& copy);
MyClass& operator=(MyClass const& copy);
~MyClass();
private
Data* d1;
Data* d2;
};
MyClass::MyClass()
:d1(NULL),d2(NULL)
{
// This is the most trivial case I can think off
// But even it looks ugly. Remember the destructor is NOT called
// unless the constructor completes (without exceptions) but if an
// exception is thrown then all fully constructed object will be
// destroyed via there destructor. But pointers don't have destructors.
try
{
d1 = new Data;
d2 = new Data;
}
catch(...)
{
delete d1;
delete d2;
throw;
}
}
Look how much easier a scopted_ptr is.
Scoped pointers are good for exactly this because they ensure that the objects get deleted without you having to worry about it as a programmer. I think that this is a good use of scoped ptr.
I find that a good design strategy in general is to avoid freeing memory manually as much as possible and let your tools (in this case smart pointers) do it for you. Manual deletion is bad for one main reason as I can see it, and that is that code becomes difficult to maintain very quickly. The logic for allocation and deallocation of memory is often separate in the code, and that leads to the complementary lines not being maintained together.
I don't think this is overkill, this documents the semantics of the member much better than having a raw pointer and is less error prone.
Why an overkill? boost::scoped_ptr is very easy to optimize, and I bet the resulting machine code would be the same as if you manually delete the pointer in the destructor.
scoped_ptr is good - just use it :)