std::move used, move constructor called but object still valid - c++

Can someone explain why the original object that is passed to a new object via std::move is still valid afterwards?
#include <iostream>
class Class
{
public:
explicit Class(const double& tt) : m_type(tt)
{
std::cout << "defaultish" << std::endl;
};
explicit Class(const Class& val) :
m_type(val.m_type)
{
std::cout << "copy" << std::endl;
};
explicit Class(Class&& val) :
m_type(val.m_type)
{
m_type = val.m_type;
std::cout << "move: " << m_type << std::endl;
};
void print()
{
std::cout << "print: " << m_type << std::endl;
}
void set(const double& tt)
{
m_type = tt;
}
private:
double m_type;
};
int main ()
{
Class cc(3.2);
Class c2(std::move(cc));
c2.print();
cc.set(4.0);
cc.print();
return 0;
}
It outputs the following:
defaultish
move: 3.2
print: 3.2
print: 4
I would expect the calls to cc.set() and cc.print() to fail...
UPDATE
Thanks to answers below, we've identified that 1) I wasn't moving anything in the move constructor, and 2) std::move() on an int or double doesn't do anything because it's more expensive to move these types than to simply copy. The new code below updates the class's private member variable to be of type std::string instead of a double, and properly calls std::move when setting this private member variable in the Class' move constructor, resulting in an output that shows how a std::move results in a valid but unspecified state
#include <iostream>
#include <string>
class Class
{
public:
explicit Class(const std::string& tt) : m_type(tt)
{
std::cout << "defaultish" << std::endl;
};
explicit Class(const Class& val) :
m_type(val.m_type)
{
std::cout << "copy" << std::endl;
};
explicit Class(Class&& val) : m_type(std::move(val.m_type))
{
std::cout << "move: " << m_type << std::endl;
};
void print()
{
std::cout << "print: " << m_type << std::endl;
}
void set(const std::string val )
{
m_type = val;
}
private:
std::string m_type;
};
int main ()
{
Class cc("3.2");
Class c2(std::move(cc));
c2.print( );
cc.print();
cc.set( "4.0" );
cc.print();
return 0;
}
And finally the output:
defaultish
move: 3.2
print: 3.2
print:
print: 4.0

Because the standard says so.
Moved-from objects have a valid but unspecified state. That means you can still use them, but you can't be sure what state they'll be in. They could look just as they did before the move, depending on what is the most efficient way to "move" data out of them. For example, "moving" from an int makes no sense (you'd have to do extra work to reset the original value!) so a "move" from an int is actually only ever going to be a copy. The same is true of a double.
Although in this case it's got more to do with the fact that you didn't actually move anything.

In the code example, std::move determines which constructor gets called. Nothing more. So c2(std::move(cc)) calls the move constructor for Class. The move constructor for Class doesn't do anything to its argument, so cc is unchanged, and it can be used just as it could have before the call to the move constructor.
All the talk in comments and answers about the state of an object that has been moved from is about the requirements on standard library types, which will be left in a "valid but unspecified state" (17.6.5.15, [lib.types.movedfrom]). What you do with your types is not affected by that.
EDIT: sigh. You edited the code and changed the question. Now that your class holds a std::string instead of a float things are different, and the std::string object in cc is, indeed, in a "valid but unspecified state".

Related

Is there a never-null unique owner of heap allocated objects?

Currently, I'm storing a collection of std::unique_ptrs to heap allocated objects of a polymorphic type:
struct Foo {
virtual ~Foo() = default;
};
Collection<std::unique_ptr<Foo>> foos;
The basic interface I need is putting / taking owners of Foo to / from foos. The objects stored in foos are never supposed to be nullptr so I'd like to replace runtime assert(owner_taken) with compile-time checks. Moreover, I would like to be capable of using non-null owners in the context where a nullable one may be expected.
Probably, I need to store something like unique_ref but how would I extract one from foos? I don't want a copy, I want the stored object itself, so owner->clone() isn't a solution. Neither I can std::move(owner) because the state of a "unique reference" would be invalid afterwards.
Is there a clean design decision?
Is there a never-null unique owner of heap allocated objects?
There is no such type in the standard library.
It is possible to implement such type. Simply define a type with unique_ptr member and mark the default constructor deleted. You can mark constructor from std::nullptr_t deleted also so that construction from nullptr will be prevented at compile time.
Whether you construct from an external pointer, or allocate in the constructor, there is no alternative for checking for null at runtime.
Reading your question, I interpret the following requirements:
You don't want to copy or move the object itself (Foo)
You don't want a wrapper which has some sort of empty state which excludes move semantics
The object itself (Foo) should be stored on the heap such that its lifetime is independent of the control flow
The object itself (Foo) should be deleted once it is not used any more
As construction / destruction, copy and move are the only ways to get objects into / out of a container, the only thing left is a wrapper object which is copied when moved into / out of the container.
You can create such an object yourself as follows:
// LICENSE: MIT
#include <memory>
#include <utility>
template<typename T>
class shared_ref {
public:
template<typename ...Args>
shared_ref(Args&&... args)
: data{new T(std::forward<Args>(args)...)}
{}
shared_ref(shared_ref&&) = delete;
shared_ref& operator=(shared_ref&&) = delete;
T& get() noexcept {
return *data;
}
const T& get() const noexcept {
return *data;
}
operator T&() noexcept {
return get();
}
operator const T&() const noexcept {
return get();
}
void swap(shared_ref& other) noexcept {
return data.swap(other);
}
private:
std::shared_ptr<T> data;
};
template<class T>
void swap(shared_ref<T>& lhs, shared_ref<T>& rhs) noexcept {
return lhs.swap(rhs);
}
I leave it as an exercise to the reader to add support for Allocator, Deleter, operator[], implicit conversion contructor to base classes.
This can then be used as follows:
#include <iostream>
int main() {
shared_ref<int> r; // default initialized
std::cout << "r=" << r << std::endl;
r = 5; // type conversion operator to reference
std::cout << "r=" << r << std::endl;
shared_ref<int> s{7}; // initialized with forwarded arguments
std::cout << "s=" << s << std::endl;
std::swap(r, s);
std::cout << "r=" << r << ", " << "s=" << s << std::endl;
s = r; // copy assignment operator
std::cout << "s=" << s << std::endl;
const shared_ref<int> t{s}; // copy constructor
std::cout << "t=" << t << std::endl;
//t = 8; // const ref from a const object is immutable
return 0;
}

Pass argument as Value

Look a this basic C++ code:
#include <iostream>
class MaClasse
{
public:
MaClasse();
void afficher();
void set(int valeur1,int valeur2);
void add1(MaClasse c2);
int _valeur1;
int _valeur2;
};
MaClasse::MaClasse()
{
std::cout << "Constructeur" << std::endl;
}
void MaClasse::afficher()
{
std::cout << _valeur1 << " " << _valeur2 << std::endl;
}
void MaClasse::add1(MaClasse c2)
{
c2._valeur1++;
c2._valeur2++;
}
void MaClasse::set(int valeur1,int valeur2)
{
_valeur1 = valeur1;
_valeur2 = valeur2;
}
int main(int argc, char *argv[])
{
MaClasse a1;
a1.set(10,20);
MaClasse a2;
a2.set(30,40);
a1.add1(a2);
a2.afficher();
return 0;
}
There is something i do not understand on this line:
a1.add1(a2);
As you can see, i do not pass a pointer but the object itself. When i display a2 values: They do not have changed.
But, i do not understand why the constructor is not called. a2 should be copied ?
Thanks
A constructor is called: the copy constructor.
Since you didn't define one yourself (you only made a default constructor), the compiler made one for you. And since it made one for you, there is no std::cout line inside it to provide the evidence!
A copy constructor will be declared like this:
MaClasse(const MaClasse&);
and be defined like this:
MaClasse::MaClasse(const MaClasse&)
{
std::cout << "Constructeur de copy" << std::endl;
}
… except you also need to make it do copy-constructory things, i.e. copy-initialising all your members.
All in, you end up with something like like:
MaClasse::MaClasse(const MaClasse& other)
: _valeur1(other._valeur1)
, _valeur2(other._valeur2)
{
std::cout << "Constructeur de copy" << std::endl;
}
Incidentally, your default constructor should also be initialising those members, probably to zero.

Force use of copy constructor / Avoid use of copy constructor

I'm currently writing a logging class (just for practice) and ran into an issue. I have two classes: The class Buffer acts as a temporary buffer and flushes itself in it's destructor. And the class Proxy that returns a Buffer instance, so I don't have to write Buffer() all the time.
Anyways, here is the code:
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
class Buffer
{
private:
std::stringstream buf;
public:
Buffer(){};
template <typename T>
Buffer(const T& v)
{
buf << v;
std::cout << "Constructor called\n";
};
~Buffer()
{
std::cout << "HEADER: " << buf.str() << "\n";
}
Buffer(const Buffer& b)
{
std::cout << "Copy-constructor called\n";
// How to get rid of this?
};
Buffer(Buffer&&) = default;
Buffer& operator=(const Buffer&) & = delete;
Buffer& operator=(Buffer&&) & = delete;
template <typename T>
Buffer& operator<<(const T& v)
{
buf << v;
return *this;
}
};
class Proxy
{
public:
Proxy(){};
~Proxy(){};
Proxy(const Proxy&) = delete;
Proxy(Proxy&&) = delete;
Proxy& operator=(const Proxy&) & = delete;
Proxy& operator=(Proxy&&) & = delete;
template <typename T>
Buffer operator<<(const T& v) const
{
if(v < 0)
return Buffer();
else
return Buffer(v);
}
};
int main () {
Buffer(Buffer() << "Test") << "what";
Buffer() << "This " << "works " << "fine";
const Proxy pr;
pr << "This " << "doesn't " << "use the copy-constructor";
pr << "This is a " << std::setw(10) << " test";
return 0;
}
Here is the output:
Copy-constructor called
HEADER: what
HEADER: Test
HEADER: This works fine
Constructor called
HEADER: This doesn't use the copy-constructor
Constructor called
HEADER: This is a test
The code does exactly what I want but it depends on RVO. I read multiple times that you should not rely on RVO so I wanted to ask how I can:
Avoid RVO completely so that the copy constructor is called every time
Avoid the copy constructor
I already tried to avoid the copy constructor by returning a reference or moving but that segfaults. I guess thats because the temporary in Proxy::operator<< is deleted during return.
I'd also be interested in completely different approaches that do roughly the same.
This seems like a contrived problem: Firstly, the code works whether RVO is enabled or disabled (you can test it by using G++ with the no-elide-constructors flag). Secondly, the way you are designing the return of a Buffer object for use with the << operator can only be done by copying†: The Proxy::operator<<(const T& v) function creates a new Buffer instance on the stack, which is then deleted when you leave the function call (i.e. between each concatenation in pr << "This " << "doesn't " << "use the copy-constructor";); This is why you get a segmentation fault when trying to reference this object from outside the function.
Alternatively, you could define a << operator to use dynamic memory by e.g. returning a unique_ptr<Buffer>:
#include <memory>
...
std::unique_ptr<Buffer> operator<<(const T& v) const
{
if(v < 0)
return std::unique_ptr<Buffer>(new Buffer());
else
return std::unique_ptr<Buffer>(new Buffer(v));
}
However, your original concatenation statements won't be compilable, then, because Proxy::operator<<(const T& v) now returns an object of type std::unique_ptr<Buffer> rather than Buffer, meaning that this returned object doesn't have its own Proxy::operator<<(const T& v) function defined and so multiple concatenations won't work without first explicitly de-referencing the returned pointer:
const Proxy pr;
std::unique_ptr<Buffer> pb = pr << "This ";
// pb << "doesn't " << "use the copy-constructor"; // This line doesn't work
*pb << "doesn't " << "use the copy-constructor";
In other words, your classes rely inherently on copying and so, if you really want to avoid copying, you should throw them away and completely re-design your logging functionalities.
† I'm sure there's some black-magic voodoo which can be invoked to make this possible --- albeit at the cost of one's sanity.

Pass by value and move, or two methods [duplicate]

This question already has answers here:
Why is value taking setter member functions not recommended in Herb Sutter's CppCon 2014 talk (Back to Basics: Modern C++ Style)?
(4 answers)
Closed 7 years ago.
Assume I have the following class, which has a method set_value. Which implementation is better?
class S {
public:
// a set_value method
private:
Some_type value;
};
Pass by value, then move
void S::set_value(Some_type value)
{
this->value = std::move(value);
}
Define two overloaded methods
void S::set_value(const Some_type& value)
{
this->value = value;
}
void S::set_value(Some_type&& value)
{
this->value = std::move(value);
}
The first approach requires definition of one method only while the second requires two.
However, the first approach seems to be less efficient:
Copy/Move constructor for the parameter depending on the argument passed
Move assignment
Destructor for the parameter
While for the second approach, only one assignment operation is performed.
Copy/Move assignment depending on which overloaded method is called
So, which implementation is better? Or does it matter at all?
And one more question: Is the following code equivalent to the two overloaded methods in the second approach?
template <class T>
void S::set_value(T&& value)
{
this->value = std::forward<T>(value);
}
The compiler is free to elide (optimise away) the copy even if there would be side effects in doing so. As a result, passing by value and moving the result actually gives you all of the performance benefits of the two-method solution while giving you only one code path to maintain. You should absolutely prefer to pass by value.
here's an example to prove it:
#include <iostream>
struct XYZ {
XYZ() { std::cout << "constructed" << std::endl; }
XYZ(const XYZ&) {
std::cout << "copy constructed" << std::endl;
}
XYZ(XYZ&&) noexcept {
try {
std::cout << "move constructed" << std::endl;
}
catch(...) {
}
}
XYZ& operator=(const XYZ&) {
std::cout << "assigned" << std::endl;
return *this;
}
XYZ& operator=(XYZ&&) {
std::cout << "move-assigned" << std::endl;
return *this;
}
};
struct holder {
holder(XYZ xyz) : _xyz(std::move(xyz)) {}
void set_value(XYZ xyz) { _xyz = std::move(xyz); }
void set_value_by_const_ref(const XYZ& xyz) { _xyz = xyz; }
XYZ _xyz;
};
using namespace std;
auto main() -> int
{
cout << "** create named source for later use **" << endl;
XYZ xyz2{};
cout << "\n**initial construction**" << std::endl;
holder h { XYZ() };
cout << "\n**set_value()**" << endl;
h.set_value(XYZ());
cout << "\n**set_value_by_const_ref() with nameless temporary**" << endl;
h.set_value_by_const_ref(XYZ());
cout << "\n**set_value() with named source**" << endl;
h.set_value(xyz2);
cout << "\n**set_value_by_const_ref() with named source**" << endl;
h.set_value_by_const_ref(xyz2);
return 0;
}
expected output:
** create named source for later use **
constructed
**initial construction**
constructed
move constructed
**set_value()**
constructed
move-assigned
**set_value_by_const_ref() with nameless temporary**
constructed
assigned
**set_value() with named source**
copy constructed
move-assigned
**set_value_by_const_ref() with named source**
assigned
note the absence of any redundant copies in the copy/move versions but the redundant copy-assignment when calling set_value_by_const_ref() with nameless temporary. I note the apparent efficiency gain of the final case. I would argue that (a) it's a corner case in reality and (b) the optimiser can take care of it.
my command line:
c++ -o move -std=c++1y -stdlib=libc++ -O3 move.cpp

How to pass by lambda in C++0x?

It seems the way to construct objects in C++0x avoiding copies/moves (particularly for large stack allocated objects) is "pass by lambda".
See the following code:
#include <iostream>
#define LAMBDA(x) [&] { return x; }
class A
{
public:
A() {};
A(const A&) { std::cout << "Copy "; }
A(A&&) { std::cout << "Move "; }
};
class B1
{
public:
B1(const A& a_) : a(a_) {}
B1(A&& a_) : a(std::move(a_)) {}
A a;
};
class B2
{
public:
B2(const A& a_) : a(a_) {}
B2(A&& a_) : a(std::move(a_)) {}
template <class LAMBDA_T>
B2(LAMBDA_T&& f, decltype(f())* dummy = 0) : a(f()) {}
A a;
};
int main()
{
A a;
std::cout << "B1 b11( a ): ";
B1 b11(a);
std::cout << std::endl;
std::cout << "B2 b12(LAMBDA(a)): ";
B2 b12(LAMBDA(a));
std::cout << std::endl;
std::cout << std::endl;
std::cout << "B1 b21( std::move(a) ): ";
B1 b21(std::move(a));
std::cout << std::endl;
std::cout << "B2 b22(LAMBDA(std::move(a))): ";
B2 b22(LAMBDA(std::move(a)));
std::cout << std::endl;
std::cout << std::endl;
std::cout << "B1 b31(( A() )): ";
B1 b31((A()));
std::cout << std::endl;
std::cout << "B2 b32((LAMBDA(A()))): ";
B2 b32((LAMBDA(A())));
std::cout << std::endl;
std::cout << std::endl;
}
Which outputs the following:
B1 b11( a ): Copy
B2 b12(LAMBDA(a)): Copy
B1 b21( std::move(a) ): Move
B2 b22(LAMBDA(std::move(a))): Move
B1 b31(( A() )): Move
B2 b32((LAMBDA(A()))):
Note the "pass by lambda" removes the move in the case where the parameter is a what I believe is called a "prvalue".
Note that it seems the "pass by lambda" approach only helps when the parameter is a "prvalue", but it doesn't seem to hurt in other cases.
Is there anyway to get functions to accept "pass by lambda" parameters in C++0x, that is nicer than the client having to wrap their parameters in lambda functions themselves? (other than defining a proxy macro that calls the function).
If you're okay with a templated constructor, you might as well use perfect forwarding instead of the obfuscation with lambdas.
class super_expensive_type {
public:
struct token_t {} static constexpr token = token_t {};
super_expensive_type(token_t);
}
constexpr super_expensive_type::token_t super_expensive_type::token;
class user {
public:
template<typename... Args>
explicit
user(Args&&... args)
: member { std::forward<Args>(args)... }
{}
private:
super_expensive_type member;
};
// ...
// only one construction here
user { super_expensive_type::token };
super_expensive_type moved_from = ...;
// one move
user { std::move(moved_from) };
super_expensive_type copied_from = ...;
// one copy
user { copied_from };
Using lambdas can't be better than this because the result from the expression in the lambda body has to be returned.
There's a fundamental problem with what you're doing. You cannot magic an object into existence. The variable must be:
Default constructed
Copy constructed
Move constructed
Constructed with a different constructor.
4 is off the table, since you only defined the first three. Your copy and move constructors both print things. Therefore, the only conclusion one can draw is that, if nothing is printed, the object is being default constructed. IE: filled with nothing.
In short, your Lambda-based transfer mechanism doesn't seem to be transferring anything at all.
After further analysis, I see what's happening. Your lambda isn't actually taking a value by reference; it's constructing a value. If you expand the macro, what you get is this:
B2 b32(([&] {return A()}));
It constructs a temporary; it doesn't actually take anything by reference. So I'm not sure how you can consider this "passing" anything. All you're doing is making a function that constructs an object. You could just as easily pass the arguments for B2::a's constructor to the constructor of B2 and have it use them to create the object, and it would give you the same effect.
You're not passing a value. You're making a function that will always create the exact same object. That's not very useful.