I have this code, taken from here by the way http://www.cplusplus.com/doc/tutorial/classes2/
// move constructor/assignment
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class Example6
{
string* ptr;
public:
Example6(const string& str) :
ptr(new string(str))
{
cout << "DONT MOVE " << '\n';
}
~Example6()
{
delete ptr;
}
// move constructor
Example6(Example6&& x) :
ptr(x.ptr)
{
cout << "MOVE " << '\n';
x.ptr = nullptr;
}
// move assignment
Example6& operator=(Example6&& x)
{
delete ptr;
ptr = x.ptr;
x.ptr = nullptr;
return *this;
}
// access content:
const string& content() const
{
return *ptr;
}
// addition:
Example6 operator+(const Example6& rhs)
{
return Example6(content() + rhs.content());
}
};
int main()
{
Example6 foo("Exam");
Example6 bar = Example6("ple"); // move-construction
foo = foo + bar; // move-assignment
cout << "foo's content: " << foo.content() << '\n';
return 0;
}
I only added output in constructor to see which is being called. To my surprise it is always the first one, copy constructor. Why does it happen? I did some research and found some info about elision. Is it somehow possible to prevent it and always call move constructor?
Also, as a side note, as I said this code is from cplusplus.com. However, I read about move semantics in some other places and I wonder if this move constructor here is done right. Shouldn't it call
ptr(move(x.ptr))
instead of just
ptr(x.ptr)
The way I understand this, if we use the second option, then we are calling copy constructor of string, instead of move, because x is rvalue reference that has a name, so it is really lvalue and we need to use move to cast it to be rvalue. Do i miss something, or is it really tutorial's mistake?
Btw, adding move doesn't solve my first problem.
So anything with a name is an lvalue.
An rvalue reference with a name is an lvalue.
An rvalue reference will bind to rvalues, but it itself is an lvalue.
So x in ptr(x.ptr) is an rvalue reference, but it has a name, so it is an lvalue.
To treat it as an rvalue, you need to do ptr( std::move(x).ptr ).
Of course, this is mostly useless, as moving a ptr does nothing as ptr is a dumb raw pointer.
You should be following the rule of 0 here.
class Example6 {
std::unique_ptr<string> ptr;
public:
Example6 (string str) : ptr(std::make_unique<string>(std::move(str))) {cout << "DONT MOVE " << '\n';}
Example6():Example6("") {}
~Example6 () = default;
// move constructor
Example6 (Example6&& x) = default;
// move assignment
Example6& operator= (Example6&& x) = default;
// access content:
const string& content() const {
if (!ptr) *this=Example6{};
return *ptr;
}
// addition:
Example6 operator+(const Example6& rhs) {
return Example6(content()+rhs.content());
}
};
because business logic and lifetime management don't belong intermixed in the same class.
While we are at it:
// addition:
Example6& operator+=(const Example6& rhs) & {
if (!ptr) *this = Example6{};
*ptr += rhs.content();
return *this;
}
// addition:
friend Example6 operator+(Example6 lhs, const Example6& rhs) {
lhs += rhs;
return lhs;
}
Copy constructor is called ... - why?
The premise of your question is faulty: The copy constructor is not called. In fact, the class is not copyable.
The first constructor is a converting constructor from std::string. The converting constructor is called because Example6 objects are initialised with a string argument. Once in each of these expressions:
Example6 foo("Exam")
Example6("ple")
Example6(content() + rhs.content()
... instead of move constructor
There are a few copy-initialisations by move in the program. However, all of them can be elided by the compiler.
Is it somehow possible to prevent it and always call move constructor?
There are a few mistakes that can prevent copy elision. For example, if you wrote the addition operator like this:
return std::move(Example6(content()+rhs.content()));
The compiler would fail to elide the move and probably tell you about it if you're lucky:
warning: moving a temporary object prevents copy elision
Shouldn't it call
ptr(move(x.ptr))
instead of just
ptr(x.ptr)
There's no need. Moving a pointer is exactly the same as copying a pointer. Same holds for all fundamental types.
The way I understand this, if we use the second option, then we are calling copy constructor of string, instead of move
ptr is not a string. It is a pointer to a string. Copying a pointer does nothing to the pointed object.
PS. The example program is quite bad quality. There should never be owning bare pointers in C++.
I can say your class does not have a copy constructor.
Because copy ctor parameter have to be const and reference
class Example6{
public:
Example6(const Example6 &r);
};
Related
I have this:
struct Point
{
size_t x;
size_t y;
~Point()
{
std::cout << "Destro" << "\n";
}
};
const Point& getPoint()
{
return { 100, 120 };
}
int main()
{
Point p = getPoint();
std::cout << "Exit" << "\n";
}
and the result is
Destro
Exit
Destro
I'm basically trying to make the getPoint method not have to copy the Point class.
Here is what's happening so far:
Point Created
Point copied to the result
Point destroyed
How can I make it so that Point is only destroyed once?
You need to return by value instead of reference. Using
Point getPoint()
{
return { 100, 120 };
}
Allows C++17's guaranteed copy elision to kick in which causes Point p = getPoint(); to act as if it was Point p{ 100, 120 };
Side note: Never, Never, Never, return a function local object by reference. That object will be destroyed at the end of the function leaving you with a dangling reference and using that is undefined behavior.
Here's an example of what it looks like you're trying to achieve...
#include <iostream>
struct Point {
size_t x;
size_t y;
~Point() { std::cout << "Destructor called\n"; }
// Explicitly deleting the Copy Constructor only to illustrate a point.
Point(const Point& other) = delete;
};
const Point makePoint(size_t a, size_t b) {
return Point{ a, b };
}
int main() {
Point a = makePoint(3, 5);
std::cout << a.x << ',' << a.y << '\n';
}
Output:
3,5
Destructor called
If you noticed, I explicitly deleted the Copy Constructor and left the Assignment Operator undeclared so that it will use the default. The struct is still using the default constructor and I didn't define a User Defined constructor.
In makePoint() I added two parameters/arguments to the function so that the user can set any values to the Point object. The function is returning a const Type object. The return statement in the function is using:
return Point{a, b};
instead of
return Point(a, b);
The latter will fail to compile because there is no user-defined constructor. However, the former works because I'm using brace-initialization. This will allow construction of the object on return instead of creating a temporary on the stack frame of the function and copying that temporary as its return value. This is a form of Copy Elision.
Now, if you want to be able to copy this object, you can remove the deleted constructor and allow the class to use its default copy constructor. The semantics of the Copy Elision will still work.
This will have the same exact results. I showed the explicit deletion of the Copy Constructor to initially prevent any Copying semantics. Then explained how the code works so you can take the original above and remove the line for the deleted copy constructor and it will still work the same:
struct Point {
size_t x;
size_t y;
~Point() { std::cout << "Destructor called\n"; }
};
const Point makePoint(size_t a, size_t b) {
return Point{ a, b };
}
The functionality or behind the scenes magic is happening within the function makePoint() and that it returns a const object and uses brace-initialization of the class.
After reading some materiales about rvalue reference i have more question then answers. From here i have read about rvalue ref:
Doc rvalue ref (1)
Doc rvalue ref (2)
Doc rvalue ref (3 - book)
Here i made a simple example to help me understand:
#include <iostream>
using namespace std;
class A
{
public:
A() :m_a(0), m_pa(nullptr) { cout << "constructor call" << endl; };
~A() { cout << "destructor call" << endl; };
A(A& other) :m_a(0), m_pa(nullptr)
{
cout << "copy constructor" << endl;
}
A(A&& other) :m_a(0), m_pa(nullptr)
{
cout << "move constructor" << endl;
}
A& operator=(A&& other)
{
this->m_a = other.m_a;
this->m_pa = other.m_pa;
other.m_a = 0;
other.m_pa = nullptr;
return *this;
}
A& operator=(A& other)
{
this->m_a = other.m_a;
this->m_pa = other.m_pa;
other.m_a = 0;
other.m_pa = nullptr;
return *this;
}
private:
int m_a;
int* m_pa;
};
int main()
{
A(test2);//constructor
A test4(test2);//copy constructor
//? - move constructor
return 0;
}
I don't understand what is so special with &&. In the above example i can do something like this with &.
A& operator=(A& other)
{
this->m_a = other.m_a; //copy value
this->m_pa = other.m_pa;//copy pointer address
other.m_a = 0;
other.m_pa = nullptr;//clean "other" object properties from preventing destructor to delete them and lose pointer address
return *this;
}
Question:
If i can do this with & without using extra memory allocation and copy operation why should i use &&?
How is a value value taken that has no identifier and saved?
Example 2:
#include <iostream>
using namespace std;
void printReference (int& value)
{
cout << "lvalue: value = " << value << endl;
}
void printReference (int&& value)
{
cout << "rvalue: value = " << value << endl;
}
int getValue ()
{
int temp_ii = 99;
return temp_ii;
}
int main()
{
int ii = 11;
printReference(ii);
printReference(getValue()); // printReference(99);
return 0;
}
Question:
Why to use && in this case and how does this help me? Why not just store the return of getValue and print it?
After you read some stuff about rvalues, here is some more material about rvalues.
I think the point you are probably missing, is not (only) what you can do but what you should do.
Your first example has several issues:
Your are not able to copy a const value to an instance of A.
const A a1;
A a2(a1); // won't compile
A a3;
a3 = a1; // won't compile
I don't understand what is so special with &&. In the above example i can do something like this with &.
Yes you could do what you suggested. But it is purely designed copy assigment. Consider this:
I wrote a shared library where my copy ctor is like you did in your suggestion. You don't have access to my code, just the header. In my copy ctor and assigment operator i take ownership of the instance you passed to my library. There is no description what the assignment is doing... Do you see the point, I must not take ownership of your instances! eg:
// my header:
// copy ctor
A& operator=(A& other);
// your code:
A a1;
A a2(a1); // from now on, a1 is broken and you don't know it!!!
cout << a1; // pseudo code: prints garbage, UD, crash!!!
You always should define copy-ctors/assignments parameters const:
A(A const& other);
A& operator=(A const& other);
// ...
const A a1;
A a2(a1); // will compile
A a3;
a3 = a1; // will compile + due to the fact a1 is passed const a3 cannot mutate a1 (does not take ownership)
cout << a1; // pseudo code: everything is fine
a3 = std::move(a1); // a3 takes ownership from a1 but you stated this explicitly as you want it
Here is a small example you can play with. Notice the copy constructor is const but the copy assignment is not. Then you can see how they differ.
If i can do this with & without using extra memory allocation and copy operation why should i use &&?
The assignment operators you wrote taking & lvalue references are very, very bad. You don't expect statements like
a = b;
to damage b, but that's what you're suggesting. The usual assignment operator takes a const& precisely because it shouldn't alter the right-hand-side of the expression.
So, you should use the rvalue-reference assignment operator (move assignment) when you do want to steal the right-hand-side's state, such as when it's an anonymous temporary or you explicitly move it:
a = return_anonymous_temporary(); // ok: the rhs value would expire anyway
a = std::move(b); // ok: the damage to b is explicit now
That behaviour shouldn't be the default, though.
If i can do this with & without using extra memory allocation and copy operation why should i use &&?
Because it allows you to overload a function for rvalues and lvalues and have different behaviour for each. You have same behaviour in both overloads, so you don't need an rvalue reference in this case.
More generally, an rvalue reference argument allows you to pass a temporary, while allowing a move from that argument.
Why to use && in this case and how does this help me?
It allowed you to print "rvalue" when the argument was an rvalue.
Why not just store the return of getValue and print it?
Then you won't be able to print "rvalue" for rvalues and "lvalue" for lvalues.
Except for move constructor/assignment operator, there are not many cases where r-values are useful.
I have read this page about the move constructor. In that article, it use the template proxy to modify the temporary variable returned from function.
This is the implemention.
namespace detail {
template <class T>
struct proxy
{
T *resource_;
};
} // detail
template <class T>
class MovableResource
{
private:
T * resource_;
public:
explicit MovableResource (T * r = 0) : resource_(r) { }
~MovableResource() throw() { delete resource_; } // Assuming std:::auto_ptr like behavior.
MovableResource (MovableResource &m) throw () // The "Move constructor" (note non-const parameter)
: resource_ (m.resource_)
{
m.resource_ = 0; // Note that resource in the parameter is moved into *this.
}
MovableResource (detail::proxy<T> p) throw () // The proxy move constructor
: resource_(p.resource_)
{
// Just copying resource pointer is sufficient. No need to NULL it like in the move constructor.
}
MovableResource & operator = (MovableResource &m) throw () // Move-assignment operator (note non-const parameter)
{
// copy and swap idiom. Must release the original resource in the destructor.
MovableResource temp (m); // Resources will be moved here.
temp.swap (*this);
return *this;
}
MovableResource & operator = (detail::proxy<T> p) throw ()
{
// copy and swap idiom. Must release the original resource in the destructor.
MovableResource temp (p);
temp.swap(*this);
return *this;
}
void swap (MovableResource &m) throw ()
{
std::swap (this->resource_, m.resource_);
}
operator detail::proxy<T> () throw () // A helper conversion function. Note that it is non-const
{
detail::proxy<T> p;
p.resource_ = this->resource_;
this->resource_ = 0; // Resource moved to the temporary proxy object.
return p;
}
};
What about just add a constructor taking a const reference and use const_cast to change the variable to implement the move semantics like this.
MovableResource(const MovableResource& m)
{
MovableResource& afterM = const_cast<MovableResource&>(m);
afterM.swap(*this);
}
Does this introduce undefined behavior?
Implementing move semantics under the hood of a copy constructor interface is just asking for trouble. By using const_cast you are effectively fooling clients of your interface into believing that your constructor will leave m unmodified when it ends up clobbering its value. Consider the following code:
const MovableResource first(/* Some resource 'A' */);
MovableResource second(first);
// 'first', supposedly 'const' now has potentially a different value!
MovableResource (MovableResource &m) throw () // The "Move constructor" (note non-const parameter)
That is not a move constructor, that is a copy constructor. A proper move constructor takes an rvalue reference as input:
MovableResource (MovableResource &&m) throw ()
MovableResource & operator = (MovableResource &m) throw () // Move-assignment operator (note non-const parameter)
Likewise, that is a copy assignment operator. A proper move assignment operator takes an rvalue reference as input:
MovableResource & operator = (MovableResource &&m) throw ()
After reading about copy constructors and copy assignment operators in C++, I tried to create a simple example. Though the below snippet apparently works, I am not sure whether I am implementing the copy constructor and copy assignment operator the right way. Could you please point out if there are any mistakes/improvements or a better example to understand the relevant concepts.
class Foobase
{
int bInt;
public:
Foobase() {}
Foobase(int b) { bInt = b;}
int GetValue() { return bInt;}
int SetValue(const int& val) { bInt = val; }
};
class Foobar
{
int var;
Foobase *base;
public:
Foobar(){}
Foobar(int v)
{
var = v;
base = new Foobase(v * -1);
}
//Copy constructor
Foobar(const Foobar& foo)
{
var = foo.var;
base = new Foobase(foo.GetBaseValue());
}
//Copy assignemnt operator
Foobar& operator= (const Foobar& other)
{
if (this != &other) // prevent self-assignment
{
var = other.var;
base = new Foobase(other.GetBaseValue());
}
return *this;
}
~Foobar()
{
delete base;
}
void SetValue(int val)
{
var = val;
}
void SetBaseValue(const int& val)
{
base->SetValue(val);
}
int GetBaseValue() const
{
return(base->GetValue());
}
void Print()
{
cout<<"Foobar Value: "<<var<<endl;
cout<<"Foobase Value: "<<base->GetValue()<<endl;
}
};
int main()
{
Foobar f(10);
Foobar g(f); //calls copy constructor
Foobar h = f; //calls copy constructor
Foobar i;
i = f;
f.SetBaseValue(12);
f.SetValue(2);
Foobar j = f = z; //copy constructor for j but assignment operator for f
z.SetBaseValue(777);
z.SetValue(77);
return 1;
}
Your copy assignment operator is implemented incorrectly. The object being assigned to leaks the object its base points to.
Your default constructor is also incorrect: it leaves both base and var uninitialized, so there is no way to know whether either is valid and in the destructor, when you call delete base;, Bad Things Happen.
The easiest way to implement the copy constructor and copy assignment operator and to know that you have done so correctly is to use the Copy-and-Swap idiom.
Only Foobar needs a custom copy constructor, assignment operator and destructor. Foobase doesn't need one because the default behaviour the compiler gives is good enough.
In the case of Foobar you have a leak in the assignment operator. You can easily fix it by freeing the object before allocating it, and that should be good enough. But if you ever add a second pointer member to Foobar you will see that that's when things get complicated. Now, if you have an exception while allocating the second pointer you need to clean up properly the first pointer you allocated, to avoid corruption or leaks. And things get more complicated than that in a polynomial manner as you add more pointer members.
Instead, what you want to do is implement the assignment operator in terms of the copy constructor. Then, you should implement the copy-constructor in terms of a non-throwing swap function. Read about the Copy & Swap idiom for details.
Also, the default constructor of Foobar doesn't default-initialize the members. That's bad, because it's not what the user would expect. The member pointer points at an arbitrary address and the int has an arbitrary value. Now if you use the object the constructor created you are very near Undefined Behaviour Land.
I have a very simple patch for you:
class Foobar
{
int var;
std::unique_ptr<FooBase> base;
...
That should get you started.
The bottom line is:
Don't call delete in your code (Experts see point 2)
Don't call delete in your code (you know better...)
I just got a seg fault in overloading the assignment operator for a class FeatureRandomCounts, which has _rects as its pointer member pointing to an array of FeatureCount and size rhs._dim, and whose other date members are non-pointers:
FeatureRandomCounts & FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs)
{
if (_rects) delete [] _rects;
*this = rhs; // segment fault
_rects = new FeatureCount [rhs._dim];
for (int i = 0; i < rhs._dim; i++)
{
_rects[i]=rhs._rects[i];
}
return *this;
}
Does someone have some clue? Thanks and regards!
*this = rhs;
calls operator=(), which is the function you are writing. Cue infinite recursion, stack overflow, crash.
Also, if you used a std::vector rather than a C-style array, you probably would not need to implement operator=() at all.
As mentioned, you have infinite recursion; however, to add to that, here's a foolproof way to implement op=:
struct T {
T(T const& other);
T& operator=(T copy) {
swap(*this, copy);
return *this;
}
friend void swap(T& a, T& b);
};
Write a correct copy ctor and swap, and exception safety and all edge cases are handled for you!
The copy parameter is passed by value and then changed. Any resources which the current instance must destroy are handled when copy is destroyed. This follows current recommendations and handles self-assignment cleanly.
#include <algorithm>
#include <iostream>
struct ConcreteExample {
int* p;
std::string s;
ConcreteExample(int n, char const* s) : p(new int(n)), s(s) {}
ConcreteExample(ConcreteExample const& other)
: p(new int(*other.p)), s(other.s) {}
~ConcreteExample() { delete p; }
ConcreteExample& operator=(ConcreteExample copy) {
swap(*this, copy);
return *this;
}
friend void swap(ConcreteExample& a, ConcreteExample& b) {
using std::swap;
//using boost::swap; // if available
swap(a.p, b.p); // uses ADL (when p has a different type), the whole reason
swap(a.s, b.s); // this 'method' is not really a member (so it can be used
// the same way)
}
};
int main() {
ConcreteExample a (3, "a"), b (5, "b");
std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n';
a = b;
std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n';
return 0;
}
Notice it works with either manually managed members (p) or RAII/SBRM-style members (s).
*this = rhs; // segment fault
This is definitively not the way to do it. You call = recursively, not calling the built in assignment operator. Assign variables one by one. Don't be lazy.
The following line:
*this = rhs; // segment fault
will recursively call your operator=() function resulting in a stack overflow.
You should probably replace it with straight-forward assignments of the various member fields.
As Neil said, using something like std::vector<> will remove much of the responsibility away from your code. If for whatever reason you can't or don't want to use std::vector<>, you might also want to consider using the 'swap idiom' for your assignment operator. This will make the function exception safe (if the allocation of the memory for FeatureCount array fails and throws an exception, the original object that's being assigned to will be left unchanged). Something like the following:
void FeatureRandomCounts::swap( FeatureRandomCounts& other)
{
FeatureCount* tmp_rects = other._rects;
int tmp_dim = other._dim; // or whatever type _dim is
// similarly for other members of FeatureRandomCounts...
// now copy the other contents to
this->_rects = other._rects;
this->_dim = other._dim;
// assign other members of rhs to lhs
other._rects = tmp_rects;
other._dim = tmp_dim;
// etc.
return;
}
Now your assignment can look like:
FeatureRandomCounts & FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs)
{
FeatureRandomCounts tmp( rhs); // make a copy
tmp.swap( *this); // swap the contents of the copy and *this
return *this;
// the contents of tmp (which has the old
// stuff that was in *this) gets destructed
}
Note that you need a proper copy constructor for this to work, but given the Big 3 rule you already need a proper copy ctor.