move and copy semantics with the std::vector - c++

How does one control which constructor/assignment operator is being used to insert elements into the std::vector class? I tried to do it by deleteing the constructor/assignment I wanted to avoid using as follows
#include<iostream>
#include<vector>
using namespace std;
class copyer{
double d;
public:
//ban moving
copyer(copyer&& c) = delete;
copyer& operator=(copyer&& c) = delete;
//copy construction
copyer(const copyer& c){
cout << "Copy constructor!" << endl;
d = c.d;
}
copyer& copy(const copyer& c){
cout << "Copy constructor!" << endl;
d = c.d;
return *this;
}
//Constructor
copyer(double s) : d(s) { }
double fn(){return d;}
};
class mover{
double d;
public:
//ban copying
mover(const mover& c) = delete;
mover& operator=(const mover& c) = delete;
//move construction
mover(mover&& c){
cout << "Move constructor!" << endl;
d = c.d;
}
mover& copy(mover&& c){
cout << "Move constructor!" << endl;
d = c.d;
return *this;
}
//Constructor
mover(double s) : d(s) { }
double fn(){return d;}
};
template<class P> class ConstrTests{
double d;
size_t N;
std::vector<P> object;
public:
ConstrTests(double s, size_t n) : d(s) , N(n) {
object.reserve(N);
for(int i = 0; i<N; i++){
object.push_back(P((double) i*d));
}
}
void test(){
int i = 0;
while(i<N){
cout << "Testing " <<i+1 << "th object: " << object.at(i).fn();
i++;
}
}
};
When I compile and run
size_t N = 10;
double d = 4.0;
ConstrTests<mover> Test1 = ConstrTests<mover>(d,N);
Test1.test();
I have no problems, but if instead I try
size_t N = 10;
double d = 4.0;
ConstrTests<copyer> Test1 = ConstrTests<copyer>(d,N);
Test1.test();
I get an error at compilation stating I'm trying to use a deleted move constructor.

If you remove these lines from copyer
//ban moving
copyer(copyer&& c) = delete;
copyer& operator=(copyer&& c) = delete;
then the code compiles fine and works as expected, that is, std::vector<copyer> uses the copy-constructor and std::vector<mover> uses the move-constructor.
You had declared copyer's move constructor and defined it as deleted. It means that copyer::copyer(copyer&& c) participates in overload resolution but if selected the code is ill formed. The call object.push_back(P((double) i*d)); triggers this call.
Why removing the lines above fixed the issue?
In old C++98 if we don't declare a copy-constructor the compiler declares and implement one for us. In C++11 this rules has changed a little bit. The compiler will not implicitly define a copy-constructor if a move constructor is user declared. (There's more on this subject but for this discussion this is enough.) Analogously, if we don't declare a move-constructor the compiler will implicitly define one for us unless we declare (for instance) a copy-constructor.
Now, after having removed the lines above, copyer will have a user declared copy-constructor buy not a move-constructor. Then, neither you nor the compiler would have declared a move-constructor. In that case, object.push_back(P((double) i*d)); will trigger a call to the copy-constructor. Notice that this is exaclty what would have happened if we compiled with a C++98 compliant compiler. In this case backward compatibility holds and old code doesn't break.

The version which is called, is determined by overload resolution. If you call push_back with a prvalue or a xvalue it'll use the move constructor, assuming your move constructor is noexcept, if it is not, it'll still use the copy constructor, if the copy constructor is deleted, you're forcing the vector to use your throwing move constructor, in which case the vector can no longer provide the strong exception guarantee. (Ie. If an exception happens from your move constructor, you've broken the content of the vector).
The general idea is, that whenever you do a push_back, reallocation may be needed, if this is the case, all elements will have to be transfered to the new memory block, using either a move or a copy constructor. Using the move constructor is generally nice, if we're sure it won't throw anything, because in the case it does, we've may already have moved some objects from the original vector, which is now broken. And moving them back is not an alternative as that may throw as well. This is why you loose the strong exception guarantee.
So in general, please do declare your move constructor noexcept, if you'd like it to be called over the copy constructor. (In the above example, if the copy constructor throws, you can just deallocate the new memory, and rethrow the exception, and the vector is still as before the push_back call).
So in general, you control which is called, based upon which constructors are available, and upon the type of the argument (lvalue vs prvalue/xvalue). Assuming your constructors are in place, you'll likely control it, by calling push_back, using std::move on it's argument, this effectively converts the argument to an xvalue, if possible.
Note; whatever I said about push_back, generally applies to insert as well.
Note2: the guarantee I'm talking about is, that whenever push_back is called, we're guaranteed that if an exception happens, the call will not have any effect, this is known as the strong exception guarantee, and it cannot be provided if all you got is a throwing move constructor.

Related

How I can be ensure that copy constructor will never be called if I use std::move

See code below. I comment move constructor and instead of compilation error, copy constructor is now called! Despite the fact that I am using std::move.
How I can be ensure, that my huge object never call copy constructor (for example, I forgot to add move constructor) if I use std::move?
class MyHugeObject
{
public:
MyHugeObject()
{
}
MyHugeObject(const MyHugeObject& m)
{
std::cout << "copy huge object\n";
}
// MyHugeObject(MyHugeObject&& m)
// {
// std::cout << "move huge object\n";
// }
};
MyHugeObject func()
{
MyHugeObject m1;
MyHugeObject&& m2 = std::move(m1);
return std::move(m2);
}
int main()
{
auto m = func();
return 0;
}
Output:
copy huge object
If copy construction of your type is especially expensive or problematic, but not something you want to completely prohibit, you can mark the copy constructor explicit. An explicit copy constructor will not allow copying if not explicitly requested (e.g. you can’t use it to automatically pass arguments by value) but will still be available for explicit copy construction. Meanwhile, implicit move construction can still be allowed.

How to elide copy when chaining?

I am creating a class of chaining-type, such as the small example below. It seems that when chaining member functions, then the copy constructor is invoked. Is there a way to get rid of the copy constructor call? In my toy example below, it is obvious that I'm only dealing with temporaries and thus there "should" (maybe not by the standards, but logically) be an elision. The second best choice, to copy elision, would be for the move constructor to be called, but this is not the case.
class test_class {
private:
int i = 5;
public:
test_class(int i) : i(i) {}
test_class(const test_class& t) {
i = t.i;
std::cout << "Copy constructor"<< std::endl;
}
test_class(test_class&& t) {
i = t.i;
std::cout << "Move constructor"<< std::endl;
}
auto& increment(){
i++;
return *this;
}
};
int main()
{
//test_class a{7};
//does not call copy constructor
auto b = test_class{7};
//calls copy constructor
auto b2 = test_class{7}.increment();
return 0;
}
Edit: Some clarifications.
1. This does not depend on optimization level.
2. In my real code, I have more complex (e.g. heap allocated) objects than ints
Partial answer (it doesn't construct b2 in place, but turns the copy construction into a move construction): You can overload the increment member function on the value category of the associated instance:
auto& increment() & {
i++;
return *this;
}
auto&& increment() && {
i++;
return std::move(*this);
}
This causes
auto b2 = test_class{7}.increment();
to move-construct b2 because test_class{7} is a temporary, and the && overload of test_class::increment is called.
For a true in-place construction (i.e. not even a move construction), you can turn all special and non-special member functions into constexpr versions. Then, you can do
constexpr auto b2 = test_class{7}.increment();
and you neither a move nor a copy construction to pay for. This is, obviously, possible for the simple test_class, but not for a more general scenario that doesn't allow for constexpr member functions.
Basically, assigning a reference to a value requires invoking a constructor, i.e. a copy or a move. This is different from copy-elision where it is known on both sides of the function to be the same distinct object. Also a reference can refer to a shared object much like a pointer.
The simplest way is probably to make the copy constructor being fully optimized away. The value setting is already optimized by the compiler, it is just the std::cout that cannot be optimized away.
test_class(const test_class& t) = default;
(or just remove both the copy and move constructor)
live example
Since your issue is basicly with the reference, a solution is probably not returning a reference to the object if you want to stop copying in this way.
void increment();
};
auto b = test_class{7};//does not call copy constructor
b.increment();//does not call copy constructor
A third method is just relying on copy elision in the first place - however this requires a rewrite or encapsulation of the operation into one function and thus avoiding the issue altogether (I'm aware this may not be what you want, but could be a solution to other users):
auto b2 = []{test_class tmp{7}; tmp.increment().increment().increment(); return tmp;}(); //<-- b2 becomes 10 - copy constructor not called
A fourth method is using a move instead, either invoked explicit
auto b2 = std::move(test_class{7}.increment());
or as seen in this answer.

Copying std::unique_ptr's value via dereferencing

I wrote the following code where I try to copy the value of unique_ptr object into a structure.
#include <iostream>
#include <memory>
using namespace std;
struct S {
S(int X = 0, int Y = 0):x(X), y(Y){}
// S(const S&) {}
// S& operator=(const S&) { return *this; }
int x;
int y;
std::unique_ptr<S> ptr;
};
int main() {
S s;
s.ptr = std::unique_ptr<S>(new S(1, 4));
S p = *s.ptr; // Copy the pointer's value
return 0;
}
It pops up errors in Visual C++ 2012:
IntelliSense: no suitable user-defined conversion from "S" to "S"
exists
IntelliSense: no operator "=" matches these operands
operand types are: std::unique_ptr> = std::unique_ptr>
error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access
private member declared in class 'std::unique_ptr<_Ty>'
Unless I uncomment the lines where I attempted to define a copy constructor and =operator.
This gets rid of the compiler errors but not the IntelliSense errors. It compiles regardless of IntelliSense errors showing in error list.
So, why cannot it just use the default functions and compile with them? Am I doing the copy of value the right way? How should I define the copy constructor if it needs one?
The copy constructor is not implicitly generated because you have a user-defined constructor, which is why your attempt to copy an S fails.
But still, unique_ptr are not copyable, only movable, so you can use a move constructor for S :
S(S&& other) : x(other.x), y(other.y), ptr(std::move(other.ptr))
{
}
And call it :
S p = std::move(s); // Move s to p
Live demo
std::unique_ptr is neither Copy Constructible nor Copy Assignable.
An implicit copy assignment operator and constructor for S will be ill formed and hence the error message.
You can however use S p = std::move(s); as std::unique_ptr is Move Constructible and Move Assignable,
Not a complete answer, just informational:
I highly recommend adding visibility into your experiment:
std::ostream&
operator<<(std::ostream& os, const S& s)
{
os << '{' << s.x << ", " << s.y << ", ";
if (s.ptr != nullptr)
os << s.ptr.get() << ':' << *s.ptr;
else
os << "nullptr";
return os << '}';
}
Now you can say things like:
cout << "s = " << s << '\n';
at multiple places in your experiment, and really get a good visual on what is happening after each step. This should help you analyze and continue in your design.
So, why cannot it just use the default functions and compile with them?
As far as I understand, the idea behind unique_ptr container is that it solely handles the life of its content (a pointer to T), until being relieved from that duty (using swap or reset methods), or having effectively destroyed its content (when it is itself destroyed). The second important property of unique_ptr is that it must allow incomplete types for T (so as to support opaque pointers). That means that the contained value may not be CopyConstructible. Because of this, unique_ptr itself cannot be allowed to be CopyConstructible.
Am I doing the copy of value the right way?
How should I define the copy constructor if it needs one?
If T ends up being CopyConstructible, as you want to do it, you must handle the copy by hand, by accessing the pointer, as you are doing it in main. The copy constructor should probably do the same thing.

C++11 Move constructor optimization

I'm currently trying to get a hang of move constructor.
I came upon the following (Compiled using g++ d.cpp --std=c++11 -O3)
class A {
string _x;
public:
A(string x) { cout << "default contrsutctor: " << x << "\n"; _x = x; }
A(const A& other) { cout << "copy contrsutctor: " << other._x << "\n"; _x = other._x; }
A(A&& other) { cout << "move contrsutctor: " << other._x << "\n"; _x = other._x; }
A foo() {
cout << "foo: " << _x << "\n";
return A("foo");
}
};
int main()
{
A a;
A b = a;
b.foo();
}
I expect this to output:
default contrsutctor: a
move contrsutctor: a
foo: a
default contrsutctor: foo
However the output is:
default contrsutctor: a
copy contrsutctor: a
foo: a
default contrsutctor: foo
Why isn't the A b = a line optimized to use the move constructor? The a object is never used afterwards, so it would be safe to optimize the code to use it instead of the copy constructor.
I know I could force the move contructor to be invoked with std::move(), but I'd prefer this to happen automatically in cases like this one.
Why isn't the A b = a line optimized to use the move constructor?
What you can do in copy constructor and move constructor could be totally different. The compiler cannot guarantee that the results of the two constructors are identical. Implementing this kind of optimization has the potential of changing the behavior of your program, which breaks the as-if rule.
You need to use std::move to cast a to A&&:
#include <utility>
int main()
{
A a("a");
A b = std::move(a);
b.foo();
}
A correct implementation of the move constructor should be:
A(A&& other)
: _x(std::move(other._x))
{}
After the line A b = std::move(a);, a should be "empty". In this case, a._x will be empty. as pointed by #TonyD in the comments, a._str could be in an unspecified but valid state (move constructor of std:string). You should use a with caution after this line.
A b = a; always invokes the copy constructor, no matter if it could invoke the move constructor. Additionally the lifetime of the object a continues after the assignment, even it is not used anymore.
If you want to use the move constructor, you have to make it explicit:
A b = std::move(a);
Note that this can be dangerous, as a is still accessible after the move. If you accidentally use it later, there may be undefined behavior.
Think about why it should happen automatically. In the example you gave, there is no need, as you can as well use a instead of b. In many cases where it would make more sense move constructor/assignment would be used automatically, e.g. A a; a = foo();.
Why isn't the A b = a line optimized to use the move constructor?
Because that would change the observable behavior of the program. The compiler is not permitted to freely change the observable behavior of the program (§1.9/1), except under very specific circumstances (§12.8/31). This is not one of those circumstances. Remove the side effects from your constructors, and the compiler may optimize them away. Of course, if you remove the side effects, then you won't notice if the compiler optimizes the constructor calls away (unless you examine the assembly or binary output), but that's the whole point.

How to prove that Copy Constructor is mandatory

I Have just created a class with an integer variable and a pointer variable. After creating its object , I passed it to a function. Even after returning the function the program is not throwing the exception
#include"iostream"
using namespace std;
class A
{
public :
int i;
char *c;
void show();
};
void func(A obj);
int main()
{
A a;
a.i = 10;
a.c = "string";
cout << " Before Fun " << endl;
a.show();
cout << " Going To Call func " << endl;
func(a);
cout << " After func " << endl;
a.show();
return 0;
}
void A::show()
{
cout << " The valuses in Object are " << i << '\t' << c << endl;
}
void func(A aa)
{
cout << " The valuses in Object are " << aa.i << '\t' << aa.c << endl;
}
In The Func I am passing the object a (from main) and it would get copied in aa (stack of func). so after returning from the func if i call show ( the pointer c would be null of a), It would give me exception
But it is not happening . please help me to prove the requirement of copy constructor
Hide the copy constructor. That will cause a compilation error everywhere it is called implicitly.
class A
{
public :
int i;
char *c;
private:
A(const A& _other);
};
If no copy constructor is declared for an object, one is implicitly defined. This copy constructor copies each element of the object.
In your example, the call to func(a) will call this copy constructor, and so aa will be a copy of a (aa.i will be 10 and aa.c will point to the first element of "string").
If you are using C++11 you can do the following to remove the copy constructor
class A
{
public :
int i;
char *c;
void operator=(const A& _other) = delete;
A(const A& _other) = delete;
};
or even better:
class A : public NonCopyable // perhaps std:: or if you prefer boost, boost::
{
public :
int i;
char *c;
};
http://en.wikipedia.org/wiki/C++11#Explicitly_defaulted_and_deleted_special_member_functions
When you make a class, a null constructor and copy constructor exist implicitly.
So that is why it does not throw an exception.
However, if you define ANY constructor, you will then need to define others otherwise the rest of the constructors will be overwritten.
For example, you define a null constructor only. Then it will throw an exception. Because the implicitly defined copy constructor will be overridden.
This is one way of proving the need of a copy constructor.
An implicit copy constructor does exist if you do not define one explicitly. It is called in your func() function. A object is copied and assigned a value for its member i.
Result will be: that you do get with show() the value for i that you had before when calling func. This is with no surprise because you are not doing any assignment to members of A inside A.
Implicit copy constructor by the compiler provide member-wise copy. This is what you may need in most cases.
When is default constructor not sufficient ? you have pointer like members, and need a deep-copy of it. You don't want to copy the pointer (what copy constructor would do), but rather to have the object pointed to copied. But why do you need deep copy ? You don't want to copy the pointer (which is owned by any instance of the class), and end up calling twice destructor on the same pointer. From the second call to delete on this pointer, heap corruption ensues. You may also need copy constructor made explicit for shared_pointers.
Note that, for performance reasons, it is best pass object by const reference than by value.
In your case the copy constructor provided by compiler is present.
Modify your code and write a copy constructor as:
//Default and copy constructor
A()
{
i = 0;
c = NULL;
}
A(const A& _other)
{
cout<<"In copy cons"<<endl;
}
When you will modify the code as per above when func gets called then your own copy constructor gets called in this case you will get the junk values(can not predict)
And if you modify your copy constructor code as
A(const A& _other)
{
cout<<"In copy cons"<<endl;
i = _other.i;
c = new char [(strlen(_other.c) +1)];
strcpy(c,_other.c);
}
Now you can see the differnce in both outputs and the use of Copy constructor how and where it's used.