I've some code that moves an object into another object. I won't need the original, moved object anymore in the upper level. Thus move is the right choice I think.
However, thinking about safety I wonder if there is a way to invalidate the moved object and thus preventing undefined behaviour if someone accesses it.
Here is a nice example:
// move example
#include <utility> // std::move
#include <vector> // std::vector
#include <string> // std::string
int main () {
std::string foo = "foo-string";
std::string bar = "bar-string";
std::vector<std::string> myvector;
myvector.push_back (foo); // copies
myvector.push_back (std::move(bar)); // moves
return 0;
}
The description says:
The first call to myvector.push_back copies the value of foo into the
vector (foo keeps the value it had before the call). The second call
moves the value of bar into the vector. This transfers its content
into the vector (while bar loses its value, and now is in a valid but
unspecified state).
Is there a way to invalidate bar, such that access to it will cause a compiler error? Something like:
myvector.push_back (std::move(bar)); // moves
invalidate(bar); //something like bar.end() will then result in a compiler error
Edit: And if there is no such thing, why?
Accessing the moved object is not undefined behavior. The moved object is still a valid object, and the program may very well want to continue using said object. For example,
template< typename T >
void swap_by_move(T &a, T &b)
{
using std::move;
T c = move(b);
b = move(a);
a = move(c);
}
The bigger picture answer is because moving or not moving is a decision made at runtime, and giving a compile-time error is a decision made at compile time.
foo(bar); // foo might move or not
bar.baz(); // compile time error or not?
It's not going to work.. you can approximate in compile time analysis, but then it's going to be really difficult for developers to either not get an error or making anything useful in order to keep a valid program or the developer has to make annoying and fragile annotations on functions called to promise not to move the argument.
To put it a different way, you are asking about having a compile time error if you use an integer variable that contains the value 42. Or if you use a pointer that contains a null pointer value. You might be succcessful in implementing an approximate build-time code convention checker using clang the analysis API, however, working on the CFG of the C++ AST and erroring out if you can't prove that std::move has not been called till a given use of a variable.
Move semantics works like that so you get an object in any it's correct state. Correct state means that all fields have correct value, and all internal invariants are still good. That was done because after move you don't actually care about contents of moved object, but stuff like resource management, assignments and destructors should work OK.
All STL classes (and all classed with default move constructor/assignment) just swap it's content with new one, so both states are correct, and it's very easy to implement, fast, and convinient enough.
You can define your class that has isValid field that's generally true and on move (i. e. in move constructor / move assignment) sets that to false. Then your object will have correct state I am invalid. Just don't forget to check it where needed (destructor, assignment etc).
That isValid field can be either one pointer having null value. The point is: you know, that object is in predictable state after move, not just random bytes in memory.
Edit: example of String:
class String {
public:
string data;
private:
bool m_isValid;
public:
String(string const& b): data(b.data), isValid(true) {}
String(String &&b): data(move(b.data)) {
b.m_isValid = false;
}
String const& operator =(String &&b) {
data = move(b.data);
b.m_isValid = false;
return &this;
}
bool isValid() {
return m_isValid;
}
}
Related
Here is the code:
class SomeType {
public:
SomeType() {}
~SomeType() {}
std::string xxx;
}
bool funtion_ab() {
SomeType(); // This is a right val;
// The right val destructs here when I test the code. I want to make sure that it would always destructs here.
int a = 0, b = 10;
....// other code
return true;
}
Please tell me if you know the truth. Thank you!
What you have is called a temporary object. From §6.7.7,
Temporary objects are created
when a prvalue is converted to an xvalue
or, more specifically,
[Note 3: Temporary objects are materialized:
...
when a prvalue that has type other than cv void appears as a discarded-value expression ([expr.context]).
— end note]
and, on the lifetime, the same section has this to say
Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.
You can read more about the expression semantics, but in your case "full-expression" is fairly unambiguous.
SomeType();
The "full-expression" containing your constructor call is... the constructor call itself. So the destructor will be called immediately after evaluating the constructor. There are some exceptions to this rule (such as if the temporary object is thrown as an exception or is bound as a reference), but none of those apply here.
As noted in the comments, compilers are free to inline your constructor and destructor calls and then are free to notice that they do nothing and omit them entirely. Optimizers can do fun stuff with your code, provided it doesn't change the semantics. But a strict reading of the standard states that the destructor is called exactly where you suggested.
I can't understand the function move in c++11.
From here, I got things below:
Although note that -in the standard library- moving implies that the
moved-from object is left in a valid but unspecified state. Which
means that, after such an operation, the value of the moved-from
object should only be destroyed or assigned a new value; accessing it
otherwise yields an unspecified value.
In my opinion, after move(), the moved-from object has been "clear". However, I've done a test below:
std::string str = "abcd";
std::move(str);
std::cout<<str;
I got abcd on my screen.
So has the str been destroyed? If so, I could get abcd because I'm just lucky? Or I misunderstood the function move?
Besides, when I read C++ Primer, I got such a code:
class Base{/* ... */};
class D: public Base{
public:
D(D&& d): Base(std::move(d)){/* use d to initialize the members of D */}
};
I'm confused now. If the function move will clear the object, the parameter d will be clear, how could we "use d to initialize the members of D"?
std::move doesn't actually do anything. It's roughly analogous to a cast expression, in that the return value is the original object, but treated differently.
More precisely, std::move returns the object in a form which is amenable to its resources being 'stolen' for some other purpose. The original object remains valid, more or less (you're only supposed to do certain special things to it, though that's primarily a matter of convention and not necessarily applicable to non-standard-library objects), but the stolen-away resources no longer belong to it, and generally won't be referenced by it any more.
But! std::move doesn't, itself, do the stealing. It just sets things up for stealing to be allowed. Since you're not doing anything with the result, let alone something which could take advantage of the opportunity, nothing gets stolen.
std::move doesn’t move anything. std::move is merely a function template that perform casts. std::move unconditionally casts its argument to an rvalue,
std::move(str);
With this expression you are just doing type cast from lvalue to rvalue.
small modification in program to understand better.
std::string str = "abcd";
std::string str1 = std::move(str);
std::cout<<str<<std::endl;
std::cout<<str1<<std::endl;
str lvalue typecast to rvalue by std::move, std::string = std::move(str); =>this expression call the string move constructor where actual stealing of resources take placed. str resources(abcd) are steeled and printed empty string.
Here is sample implementation of move function. Please note that it is not complete implementation of standard library.
template<typename T> // C++14; still in
decltype(auto) move(T&& param) // namespace std
{
using ReturnType = remove_reference_t<T>&&;
return static_cast<ReturnType>(param);
}
Applying std::move to an object tells the compiler that the object is eligible to be moved from. It cast to the rvalue.
class Base{/* ... */};
class D: public Base{
public:
D(D&& d): Base(std::move(d)){/* use d to initialize the members of D */}
};
Base(std::move(d)) it will do up-casting only move the base class part only.
Here one more interesting thing to learn for you. If you do not invoke base class destructor with std::move like D(D&& d): Base(d) then d will be considered as lvalue and copy constructor of Base class involved instead of move constructor. Refer for more detail Move constructor on derived object
I have the following member variable in a class:
std::vector<std::unique_ptr<Object>> objects_;
I explicitly want the vector to maintain ownership at all times. I've seen suggestions that in order for a member function to access a pointer in the vector and make changes to the object T wrapped in the std::unique_ptr, we must move the pointer to calling code, i.e:
void foo(int i) {
auto object = std::move( vector.at( i ) ); // move object to caller (caller owns)
object->dosomething();
vector.at(i) = std::move(object); // move back into vector (vector owns)
}
Another method was to work with raw pointers:
void foo(int i) {
Object* object = vector.at( i ).get();
object->doSomething();
}
However, I've been working with this:
void foo(int i) {
auto& object = vector.at( i );
object->doSomething();
}
Which is the correct and most robust method for my case? Does this function ever take ownership of the data in the std::unique_ptr? Is there a way to access Object without playing with the std::unique_ptr?
(excuse me if my methods are incorrect, I hope I got the point across)
The first approach will not retain ownership of the object if object->dosomething() throws an exception (i.e. it is not exception safe) since the second std::move() statement will not be executed.
Assuming C++11, both of the other approaches are effectively equivalent, subject to the assumption that the owned pointer is not null. Under the same assumption, the code can be simplified to
void foo(int i)
{
vector.at(i)->doSomething();
}
which will work with all C++ standards (not just C++11 or later).
It is possible to access the object without monkeying with the unique_ptr - simply store the pointer elsewhere and use that. However, that does compromise the purpose of using std::unique_ptr in the first place. And is error-prone - for example, the std::unique_ptr can destroy the object, and leave those other pointers dangling.
If you are really that worried about the potential of your vector losing ownership, consider using a shared_ptr instead.
In the following example, why doesn't the move constructor get called in the construction of 'copy' inside fun, even though the 'src' argument of 'fun' is explicitly a rvalue reference and is only used in that construction?
struct Toy {
int data;
Toy(): data(0)
{
log("Constructed");
}
Toy(Toy const& src): data(src.data)
{
log("Copy-constructed");
}
Toy(Toy&& src): data(src.data)
{
log("Move-constructed");
}
};
Toy fun(Toy&& src)
{
Toy copy(src);
copy.data = 777;
return copy;
}
Toy toy(fun(Toy())); // LOG: Constructed Copy-constructed
While Bob && b is an rvalue reference, all named use of data after construction is using it as an lvalue.
So Bob&& b will only bind to rvalues, but when you use it it will not move.
The only ways to get an rvalue reference are:
A value without a name, such as a temporary return value or result of a cast.
Use of a local value variable in a simple return x; statement.
Explicitly casting to an rvalue, such as with std::move or std::forward.
This prevents data from being silently moved from on one line and then used on the next. It can help to think of rvalue as being 'I the programmer say this is not needed after this expression' at use, and 'only take things that are not needed afterwards' in function parameters. The temporary/return exceptions above are two spots the compiler can relatively safely guarantee this itself.
Finally, note that universal references (auto&& and T&&) look like rvalue references but sometimes are not.
struct STest : public boost::noncopyable {
STest(STest && test) : m_n( std::move(test.m_n) ) {}
explicit STest(int n) : m_n(n) {}
int m_n;
};
STest FuncUsingConst(int n) {
STest const a(n);
return a;
}
STest FuncWithoutConst(int n) {
STest a(n);
return a;
}
void Caller() {
// 1. compiles just fine and uses move ctor
STest s1( FuncWithoutConst(17) );
// 2. does not compile (cannot use move ctor, tries to use copy ctor)
STest s2( FuncUsingConst(17) );
}
The above example illustrates how in C++11, as implemented in Microsoft Visual C++ 2012, the internal details of a function can modify its return type. Up until today, it was my understanding that the declaration of the return type is all a programmer needs to know to understand how the return value will be treated, e.g., when passed as a parameter to a subsequent function call. Not so.
I like making local variables const where appropriate. It helps me clean up my train of thought and clearly structure an algorithm. But beware of returning a variable that was declared const! Even though the variable will no longer be accessed (a return statement was executed, after all), and even though the variable that was declared const has long gone out of scope (evaluation of the parameter expression is complete), it cannot be moved and thus will be copied (or fail to compile if copying is not possible).
This question is related to another question, Move semantics & returning const values. The difference is that in the latter, the function is declared to return a const value. In my example, FuncUsingConst is declared to return a volatile temporary. Yet, the implementational details of the function body affect the type of the return value, and determine whether or not the returned value can be used as a parameter to other functions.
Is this behavior intended by the standard?
How can this be regarded useful?
Bonus question: How can the compiler know the difference at compile time, given that the call and the implementation may be in different translation units?
EDIT: An attempt to rephrase the question.
How is it possible that there is more to the result of a function than the declared return type? How does it even seem acceptable at all that the function declaration is not sufficient to determine the behavior of the function's returned value? To me that seems to be a case of FUBAR and I'm just not sure whether to blame the standard or Microsoft's implementation thereof.
As the implementer of the called function, I cannot be expected to even know all callers, let alone monitor every little change in the calling code. On the other hand, as the implementer of the calling function, I cannot rely on the called function to not return a variable that happens to be declared const within the scope of the function implementation.
A function declaration is a contract. What is it worth now? We are not talking about a semantically equivalent compiler optimization here, like copy elision, which is nice to have but does not change the meaning of code. Whether or not the copy ctor is called does change the meaning of code (and can even break the code to a degree that it cannot be compiled, as illustrated above). To appreciate the awkwardness of what I am discussing here, consider the "bonus question" above.
I like making local variables const where appropriate. It helps me clean up my train of thought and clearly structure an algorithm.
That is indeed a good practice. Use const wherever you can. Here, however, you cannot (if you expect your const object to be moved from).
The fact that you declare a const object inside your function is a promise that your object's state won't ever be altered as long as the object is alive - in other words, never before its destructor is invoked. Not even immediately before its destructor is invoked. As long as it is alive, the state of a const object shall not change.
However, here you are somehow expecting this object to be moved from right before it gets destroyed by falling out of scope, and moving is altering state. You cannot move from a const object - not even if you are not going to use that object anymore.
What you can do, however, is to create a non-const object and access it in your function only through a reference to const bound to that object:
STest FuncUsingConst(int n) {
STest object_not_to_be_touched_if_not_through_reference(n);
STest const& a = object_not_to_be_touched_if_not_through_reference;
// Now work only with a
return object_not_to_be_touched_if_not_through_reference;
}
With a bit of discipline, you can easily enforce the semantics that the function should not modify that object after its creation - except for being allowed to move from it when returning.
UPDATE:
As suggested by balki in the comments, another possibility would be to bind a constant reference to a non-const temporary object (whose lifetime would be prolonged as per § 12.2/5), and perform a const_cast when returning it:
STest FuncUsingConst(int n) {
STest const& a = STest();
// Now work only with a
return const_cast<STest&&>(std::move(a));
}
A program is ill-formed if the copy/move constructor [...] for an object is implicitly odr-used and the special member function is not accessible
-- n3485 C++ draft standard [class.copy]/30
I suspect your problem is with MSVC 2012, and not with C++11.
This code, even without calling it, is not legal C++11:
struct STest {
STest(STest const&) = delete
STest(STest && test) : m_n( std::move(test.m_n) ) {}
explicit STest(int n) : m_n(n) {}
int m_n;
};
STest FuncUsingConst(int n) {
STest const a(n);
return a;
}
because there is no legal way to turn a into a return value. While the return can be elided, eliding the return value does not remove the requirement that the copy constructor exist.
If MSVC2012 is allowing FuncUsingConst to compile, it is doing so in violation of the C++11 standard.