By the requeriments specified by the std::input_iterator concept, (and supperior iterators seems to be the same), they have to provide copy and move constructors:
input_iter<T>(const input_iter<T>& other) = default;
input_iter<T>(input_iter<T>&& other) noexcept = default;
Can they be defaulted? The typical implementation contains a private member pointing to some data:
private:
T* data;
Is in iterators a shallow copy/move the desired behaviour? I mean, copy/move the pointer itself, or must implement an explicit deep copy?
Iterators don't own the pointed object, they just point to it. So copying whatever member pointers suffices.
Related
What does it mean that implicit move constructor does a member-wise move and implicit move assignment operator a member-wise assignment?
From https://en.cppreference.com/w/cpp/language/move_constructor:
For non-union class types (class and struct), the move constructor
performs full member-wise move of the object's bases and non-static
members, in their initialization order, using direct initialization
with an xvalue argument. If this satisfies the requirements of a
constexpr constructor, the generated move constructor is constexpr.
From https://en.cppreference.com/w/cpp/language/move_assignment:
For non-union class types (class and struct), the move assignment
operator performs full member-wise move assignment of the object's
direct bases and immediate non-static members, in their declaration
order, using built-in assignment for the scalars, memberwise
move-assignment for arrays, and move assignment operator for class
types (called non-virtually).
Will the implicit members look like this for the following exemplary class template:
template<class T>
class Holder {
public:
Holder(int size) : m_size(size) { m_data = new T[m_size]; }
Holder(Holder && other) :
m_size(std::move(other.m_size)),
m_data(std::move(other.m_data))
{}
Holder& operator=(Holder && other) {
if(this == &other) return *this;
m_data = std::move(other.m_data);
m_size = std::move(other.m_size);
return *this;
}
~Holder() { delete [] m_data; }
private:
T* m_data;
int m_size;
};
What's more, what will the std::move() in the above example transfer the resources?
If you look further down you linked page, you will see that your classes compiler generated move constructor (and move assignment operator) will actually be Trivial:
Trivial move constructor
The move constructor for class T is trivial if all of the following is true:
it is not user-provided (meaning, it is implicitly-defined or defaulted);
T has no virtual member functions;
T has no virtual base classes
the move constructor selected for every direct base of T is trivial;
the move constructor selected for every non-static class type (or array of class type) member of T is trivial;
A trivial move constructor is a constructor that performs the same action as the trivial copy constructor, that is, makes a copy of the
object representation as if by std::memmove. All data types
compatible with the C language (POD types) are trivially movable.
(Emphasis mine)
The two member variables are POD types and therefore are trivially movable. Since your class is not virtual and it holds no non-trivial members it is therefore trivial and all the data members will be copied. As mentioned in the comments, this will lead to double deleting your pointer and UB.
Since this is the case, you need to implement your move semantics properly, by taking ownership of the moved objects pointer and setting it to nullptr. Or better yet, just use std::vector or even std::unique_ptr.
I'm trying to move things in and out from my thead safe deque:
template <typename T>
class ThreadSafeDeque
{
//..
T pop_front(void) noexcept
{
std::unique_lock<std::mutex> lock{_mutex};
while (_collection.empty())
{
_condNewData.wait(lock);
}
auto elem = std::move(_collection.front());
_collection.pop_front();
return elem;
}
private:
std::deque<T> _collection; // Concrete, not thread safe, storage.
//...
}
I created this class to insert into the Deque:
class DecodedFrame
{
public:
DecodedFrame(){}
DecodedFrame(const DecodedFrame &decodedFrame) = delete;
DecodedFrame &operator=(const DecodedFrame &) = delete;
std::unique_ptr<AVFrame, AVFrameDeleter> avFrame;
Now I'm trying to do
std::shared_ptr<ThreadSafeDeque<DecodedFrame>> decodedFramesFifo;
//add some `DecodedFrame`s to decodedFramesFifo
DecodedFrame decodedFrame = std::move(decodedFramesFifo->pop_front());
But the compiler complains that I deleted the copy assignment constructor, even though I'm trying to use the move assingment constructor. My guess is that it happens because pop_front returns T, not T&. However, returning references makes no sense becaue the object is supposed to leave the deque forever and therefore the reference to it will die.
How can I move things here?
ps: how is it possible for the compiler to copy things when the DecodedFrame holds an unique_ptr? It can't be copied!
The problem is you declared your copy c'tor and assignment operator. Doesn't matter that the declaration deletes them, it's still a user supplied declaration. That suppresses the implicit declaration of the move operations. Your options are to
Default the move operations explicitly.
Remove the copy operation declarations, they will still be deleted implicitly on account of the noncopyable member.
The copy-ctor/assign operations are deleted (these are also declarations) but that does not implicitly declare/define move-ctor/assign operations.
See p30 of https://fr.slideshare.net/ripplelabs/howard-hinnant-accu2014
You have to declare (default) them.
DecodedFrame(DecodedFrame &&) = default;
DecodedFrame &operator=(DecodedFrame &&) = default;
In order to avoid such frustrating behaviour, you should consider the rule of five.
(https://en.cppreference.com/w/cpp/language/rule_of_three#Rule_of_five)
You dont get the move constructor and move assignment operator because your copy constructor and copy assignment operator are user delcared/defined (you deleted them). you can force the default move constructor and move assignment via "=default" (like you did with delete).
But because the class has a unique pointer as member which itself is only move constructible and move assignable, you will get the deletion of the copy constructor and copy assignment for free. just remove you delete statements and you will be fine, since you then again get the move operations.
The title pretty much sums up my question. In more detail: I know that when I declare a move constructor and a move assignment operator in C++11 I have to "make the other objects variables zero". But how does that work, when my variable is not an array or a simple int or double value, but its a more "complex" type?
In this example I have a Shoplist class with a vector member variable. Do I have to invoke the destructor of the vector class in the move assignment operator and constructor? Or what?
class Shoplist {
public:
Shoplist() :slist(0) {};
Shoplist(const Shoplist& other) :slist(other.slist) {};
Shoplist(Shoplist&& other) :slist(0) {
slist = other.slist;
other.slist.~vector();
}
Shoplist& operator=(const Shoplist& other);
Shoplist& operator=(Shoplist&& other);
~Shoplist() {};
private:
vector<Item> slist;
};
Shoplist& Shoplist::operator=(const Shoplist& other)
{
slist = other.slist;
return *this;
}
Shoplist& Shoplist::operator=(Shoplist&& other)
{
slist = other.slist;
other.slist.~vector();
return *this;
}
Whatever a std::vector needs to do in order to move correctly, will be handled by its own move constructor.
So, assuming you want to move the member, just use that directly:
Shoplist(Shoplist&& other)
: slist(std::move(other.slist))
{}
and
Shoplist& Shoplist::operator=(Shoplist&& other)
{
slist = std::move(other.slist);
return *this;
}
In this case, you could as AndyG points out, just use = default to have the compiler generate exactly the same move ctor and move assignment operator for you.
Note that explicitly destroying the original as you did is definitely absolutely wrong. The other member will be destroyed again when other goes out of scope.
Edit: I did say assuming you want to move the member, because in some cases you might not.
Generally you want to move data members like this if they're logically part of the class, and much cheaper to move than copy. While std::vector is definitely cheaper to move than to copy, if it holds some transient cache or temporary value that isn't logically part of the object's identity or value, you might reasonably choose to discard it.
Implementing copy/move/destructor operations doesn't make sense unless your class is managing a resource. By managing a resource I mean be directly responsible for it's lifetime: explicit creation and destruction. The rule of 0 and The rule of 3/5 stem from this simple ideea.
You might say that your class is managing the slist, but that would be wrong in this context: the std::vector class is directly (and correctly) managing the resources associated with it. If you let our class have implicit cpy/mv ctos/assignment and dtors, they will correctly invoke the corresponding std::vector operations. So you absolutely don't need to explicitly define them. In your case the rule of 0 applies.
I know that when I declare a move constructor and a move assignment
operator in C++11 I have to "make the other objects variables zero"
Well no, not really. The ideea is that when you move from an object (read: move it's resource from an object) then you have to make sure that your object it's left aware that the resource it had is no more under it's ownership (so that, for instance, it doesn't try to release it in it's destructor). In the case of std::vector, it's move ctor would set the pointer it has to the internal buffer to nullptr.
I know that when I declare a move constructor and a move assignment operator in C++11 I have to "make the other objects variables zero"
This is not quite correct. What you must do, is maintain validity of the moved from object. This means that you must satisfy the class invariant.
If you have specified a special invariant for a particular class, that requires you to set member variables to zero, then perhaps such class might have to do so. But this is not a requirement for move in general.
Do I have to invoke the destructor of the vector class in the move assignment operator and constructor?
Definitely not. The destructors of the members will be called when the moved from object is destroyed.
What you would typically do, is move construct/assign each member in the move constructor/assignment operator of the containing object. This is what the implicitly generated special member functions do. Of course, this might not satisfy the class invariant for all classes, and if it doesn't, then you may need to write your own versions of them.
The compiler will implicitly generate the special member functions for you, if you don't try to declare them yourself. Here is a minimal, but correct version of your class:
class Shoplist {
vector<Item> slist;
};
This class is default constructible, movable and copyable.
The move constructor should move member-wise:
Shoplist(Shoplist&& other)
: slist(std::move(other.slist))
{}
Note, that the compiler generates move constructors for you (when possible) by member-wise move, as you would do by hand above.
Move constructors are allowed (but not required) "steal" the contents of the moved-from object. This does not mean that they must "make the other objects variables zero". Moving a primitive type, for instance, is equivalent to copying it. What it does mean is that a move constructor can transfer ownership of data in the heap or free store. In this case, the moved-from object must be modified so that when it is destroyed (which should not happen in the move-constructor), the data it previously owned (before it was transferred) will not be freed.
Vector provides its own move constructor. So all you need to do in order to write a correct move constructor for an object containing a vector is to ensure the correct vector constructor is invoked. This is done by explicitly passing an r-value reference to the sub-object constructor, using std::move:
Shoplist(Shoplist&& other) :slist(std::move(other.slist)) {
//... Constructor body
... But in fact you probably don't need to do this in general. Your copy and move constructors will be correctly auto-generated if you don't declare them and don't declare a destructor. (Following this practice is called the "rule of 0".)
Alternatively, you can force the compiler to auto-generate the move constructor:
Shoplist(Shoplist&& other) = default;
When I learned C++ people told me to always implement at least rule of three methods.
Now I'm seeing the new "... = default;" from c++0x on stack overflow, and my question is:
Is there a c++11 standard implementation defined for those methods or is it compiler specific?
plus I would like to have some precisions:
What does the implementation looks like in term of code? (if it's generic)
Does this have an advantage compared to my example implementation below?
If you don't use assignment/copy constructor, what does *... = delete* do precisly, what's the difference with declaring them private? Answer (from #40two)
Is the new default= different from the old default implementation?
Disclaimer: when I'll need more advanced features in my methods, for sure I'll implements them myself. But I get used to implement assignment operator and copy constructor even when I never used them, just in order that the compiler don't.
What I used to do: (edited, #DDrmmr swap/move)
//File T.h
class T
{
public:
T(void);
T(const T &other);
T(const T &&other);
T &operator=(T other);
friend void swap(T &first, T &second);
~T(void);
protected:
int *_param;
};
//File T.cpp
T::T(void) :
_param(std::null)
{}
T::T(T &other)
: _param(other._param)
{}
T::T(T &&other)
: T()
{
swap(*this, other);
}
T &T::operator=(T other)
{
swap(*this, other);
return (*this);
}
friend void swap(T &first, T &second)
{
using std::swap;
swap(first._param, second._param);
}
T::~T(void)
{}
The default behavior is:
Default ctor ( T() ): calls bases def. ctors and members default ctors.
Copy ctor ( T(const T&) ): calls bases copy. ctors and members copy ctors.
Move ctor ( T(T&&) ): calls bases move. ctors and members move ctors.
Assign ( T& operator=(const T&) ): calls bases assign. and members assign.
Transfer ( T& operator=(T&&) ): calls bases transfer, and members transfer.
Destructor ( ~T() ): calls member destructor, and bases destructor (reverse order).
For built-in types (int etc.)
Default ctor: set to 0 if explicitly called
Copy ctor: bitwise copy
Move ctor: bitwise copy (no change on the source)
Assign: bitwise copy
Transfer: bitwise copy
Destructor: does nothing.
Since pointers are builtin types as well, this apply to int* ( not to what it points to).
Now, if you don't declare anything, your T class will just hold a int* that does not own the pointed int, so a copy of T will just hold a pointer to the same int. This is the same resulting behavior as C++03. Default implemented move for built-in types are copy. For classes are memberwise move (and depends on what members are: just copies for built-ins)
If you have to change this behavior, you have to do it coherently: for example, if you want to "own" what you point to, you need
a default ctor initializing to nullptr: this defines an "empty state" we can refer later
a creator ctor initializing to a given pointer
a copy ctor initializing to a copy of the pointed (this is the real change)
a dtor that deletes the pointed
an assign that deletes the pointed and receive a new copy of the pointed
.
T::T() :_param() {}
T::T(int* s) :_param(s) {}
T(const T& s) :_param(s._param? new int(*s._param): nullptr) {}
~T() { delete _param; } // will do nothing if _param is nullptr
Let's not define the assign, by now, but concentrate on the move:
If you don't declare it, since you declared the copy, it will be deleted: this makes a T object always being copied even if temporary (same behavior as c++03)
But if the source object is temporary, we can create an empty destination and swap them:
T::T(T&& s) :T() { std::swap(_param, s._param); }
This is what is called a move.
Now the assignment: before C++11 T& operator=(const T& s) should check against a self assignment, make the destination empty and receive a copy of the pointed:
T& operator=(const T& s)
{
if(this == &s) return *this; // we can shortcut
int* p = new int(s._param); //get the copy ...
delete _param; //.. and if succeeded (no exception while copying) ...
_param = p; // ... delete the old and keep the copy
return *this;
}
With C++11 we can use the parameter passing to generate the copy, thus giving
T& operator=(T s) //note the signature
{ std::swap(_param, s._param); return *this; }
Note that this works also in C++98, but the pass-by copy will not be optimized in pass-by move if s is temporary. This makes such implementation not profitable in C++98 and C++03 but really convenient in C++11.
Note also that there is no need to specialize std::swap for T: std::swap(a,b); will work, being implemented as three moves (not copy)
The practice to implement a swap function derives for the case where T has many members, being swap required in both move and assign. But it can be a regular private member function.
If the operator= is properly defined, is it OK to use the following as copy constructor?
MyClass::MyClass(MyClass const &_copy)
{
*this = _copy;
}
If all members of MyClass have a default constructor, yes.
Note that usually it is the other way around:
class MyClass
{
public:
MyClass(MyClass const&); // Implemented
void swap(MyClass&) throw(); // Implemented
MyClass& operator=(MyClass rhs) { rhs.swap(*this); return *this; }
};
We pass by value in operator= so that the copy constructor gets called. Note that everything is exception safe, since swap is guaranteed not to throw (you have to ensure this in your implementation).
EDIT, as requested, about the call-by-value stuff: The operator= could be written as
MyClass& MyClass::operator=(MyClass const& rhs)
{
MyClass tmp(rhs);
tmp.swap(*this);
return *this;
}
C++ students are usually told to pass class instances by reference because the copy constructor gets called if they are passed by value. In our case, we have to copy rhs anyway, so passing by value is fine.
Thus, the operator= (first version, call by value) reads:
Make a copy of rhs (via the copy constructor, automatically called)
Swap its contents with *this
Return *this and let rhs (which contains the old value) be destroyed at method exit.
Now, we have an extra bonus with this call-by-value. If the object being passed to operator= (or any function which gets its arguments by value) is a temporary object, the compiler can (and usually does) make no copy at all. This is called copy elision.
Therefore, if rhs is temporary, no copy is made. We are left with:
Swap this and rhs contents
Destroy rhs
So passing by value is in this case more efficient than passing by reference.
It is more advisable to implement operator= in terms of an exception safe copy constructor. See Example 4. in this from Herb Sutter for an explanation of the technique and why it's a good idea.
http://www.gotw.ca/gotw/059.htm
This implementation implies that the default constructors for all the data members (and base classes) are available and accessible from MyClass, because they will be called first, before making the assignment. Even in this case, having this extra call for the constructors might be expensive (depending on the content of the class).
I would still stick to separate implementation of the copy constructor through initialization list, even if it means writing more code.
Another thing: This implementation might have side effects (e.g. if you have dynamically allocated members).
While the end result is the same, the members are first default initialized, only copied after that.
With 'expensive' members, you better copy-construct with an initializer list.
struct C {
ExpensiveType member;
C( const C& other ): member(other.member) {}
};
};
I would say this is not okay if MyClass allocates memory or is mutable.
yes.
personally, if your class doesn't have pointers though I'd not overload the equal operator or write the copy constructor and let the compiler do it for you; it will implement a shallow copy and you'll know for sure that all member data is copied, whereas if you overload the = op; and then add a data member and then forget to update the overload you'll have a problem.
#Alexandre - I am not sure about passing by value in assignment operator. What is the advantage you will get by calling copy constructor there? Is this going to fasten the assignment operator?
P.S. I don't know how to write comments. Or may be I am not allowed to write comments.
It is technically OK, if you have a working assignment operator (copy operator).
However, you should prefer copy-and-swap because:
Exception safety is easier with copy-swap
Most logical separation of concerns:
The copy-ctor is about allocating the resources it needs (to copy the other stuff).
The swap function is (mostly) only about exchanging internal "handles" and doesn't need to do resource (de)allocation
The destructor is about resource deallocation
Copy-and-swap naturally combines these three function in the assignment/copy operator