As I know std::move (same as static_cast<T&&>) casts variable to rvalue and assigns to lvalue, and because of this I think in following code:
int a = 1;
int b = static_cast<int&&>(a);
b and a have the same address, but in VS, it prints different addresses.
int a = 1;
int b = static_cast<int&&>(a);
cout << hex << &a << endl;
cout << hex << &b << endl;
If after this a still points to a different memory location, what is the benefit of using std::move in this case?
Just because you "move" them doesn't mean they will share the same address. Moving a value is a high level abstraction, with basic types like int moving and copying is completely the same, which is happening here. I suggest you read the excellent post on std::move to know what it does and what it's uses are.
No, b is its own object, which is copy initialized from an rvalue reference to another int. This is the same as just copying the referenced object.
Move semantics only shines when the "copying" can be preformed by resource stealing (since we know the other objects storage is about to go, anyway).
For a type like an integer, it's still a plain copy.
There is no benefit of using std::move on an int. In your example you are basically copying the value from a to b.
Move semantics is only meaningfull on resources where you want to transfer ownership, e.g. dynamically allocated memory. Take the std::unique_ptr as an example.
auto ptr = std::make_unique<int>(1);
auto ptrCopy = ptr; // copy will not work compilation error.
auto ptrMove = std::move(ptr);
In the above example ptrMove has taken over the ownership of ptr and ptr is now empty.
When you use std::move in C++ you do not move the object itself, you move the value of the object or its contents. So its address does not change.
Moving is no different from copying with an int. But for a complex type with internal pointers to allocated memory, that memory can be transferred without copying using a std::move (assuming it has been designed to respond to std::move).
Related
A note: this is an API design question, riding on the design of the constructors of unique_ptr and share_ptr for the sake of the question, but not aiming to propose any change to their current specifications.
Though it would usually be advisable to use make_unique and make_shared, both unique_ptr and shared_ptr can be constructed from a raw pointer.
Both get the pointer by value and copy it. Both allow (i.e. in the sense of: do not prevent) a continuance usage of the original pointer passed to them in the constructor.
The following code compiles and results with double free:
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
Both unique_ptr and shared_ptr could prevent the above if their relevant constructors would expect to get the raw pointer as an rvalue, e.g. for unique_ptr:
template<typename T>
class unique_ptr {
T* ptr;
public:
unique_ptr(T*&& p) : ptr{p} {
p = nullptr; // invalidate the original pointer passed
}
// ...
Thus, the original code would not compile as an lvalue cannot bind to an rvalue, but using std::move the code compiles, while being more verbose and more secured:
int* ptr = new int(9);
std::unique_ptr<int> p { std::move(ptr) };
if (!ptr) {
// we are here, since ptr was invalidated
}
It is clear that there can be dozens of other bugs a user can do with smart pointers. The commonly used argument of you should know how to properly use the tools provided by the language, and C++ is not designed to watch over you etc.
But still, it seems that there could have been an option for preventing this simple bug and to encourage usage of make_shared and make_unique. And even before make_unique was added in C++14, there is still always the option of direct allocation without a pointer variable, as:
auto ptr = std::unique_ptr<int>(new int(7));
It seems that requesting rvalue reference to a pointer as the constructor parameter could add a bit of an extra safety. Moreover, the semantics of getting rvalue seems to be more accurate as we take ownership of the pointer that is passed.
Coming to the question of why didn't the standard take this more secured approach?
A possible reason might be that the approach suggested above would prevent creating a unique_ptr from const pointers, i.e. the following code would fail to compile with the proposed approach:
int* const ptr = new int(9);
auto p = std::unique_ptr { std::move(ptr) }; // cannot bind `const rvalue` to `rvalue`
But this seems to be a rare scenario worth neglecting, I believe.
Alternatively, in case the need to support initialization from a const pointer is a strong argument against the proposed approach, then a smaller step could still be achieved with:
unique_ptr(T* const&& p) : ptr{p} {
// ...without invalidating p, but still better semantics?
}
As long as they both have a get() method, invalidating the original pointer is not a "more secured", but a more confusing approach.
In the way raw pointers are used in C++, they don't represent any ownership concept by themselves and don't define the object lifetime. Anyone who uses raw pointers in C++ needs to be aware that they are only valid while the object exists (whether the object lifetime is enforced by smart pointers or by the logic of the program). Creating a smart pointer from a raw pointer does not "transfer" ownership of the object, but "assigns" it.
This distinction could be made clear in the following example:
std::unique_ptr<int> ptr1 = std::make_unique<int>(1);
int* ptr2 = ptr1.get();
// ...
// somewhere later:
std::unique_ptr<int> ptr3(ptr2);
// or std::unique_ptr<int> ptr3(std::move(ptr2));
In this case, the ownership of the int object is not transferred to the ptr3. It is erroneously assigned to it without releasing the ownership by ptr1. A programmer needs to be aware where the pointer passed to the std::unique_ptr constructor comes from, and how the ownership of the object has been enforced so far. An assurance by the library that it will invalidate this particular pointer variable may give the programmer a false sense of security, but does not provide any real safety.
I think the answer is simple: zero overhead. This change isn't needed for unique_ptr to be functional, so the standard doesn't require it. If you think this improves safety enough to worth it, you can ask your implementation to add it (maybe under a special compilation flag).
BTW, I'd expect static analyzers to know enough to warn against this code pattern.
Hello so i am trying to understand what is going on under the hood.
int* puter;
puter = std::make_unique<int>(50).get();
if(puter) { std::cout << *puter << std::endl; }
At first i thought the puter should be a dangling ptr because temporary unique_ptr from make_unique would be destroyed along with the allocated resource. But that is not the case.
After a while i could understand that it might not happen if the unique_ptr resource was move assigned to puter.
But the real question is. When should i assume things will get move asigned from temporary? Is there a rule to it? Should i just use release method for assurance in such cases?
As others have mentioned, this actually triggers undefined behaviors.
Your original thought is exactly what happened
At first i thought the puter should be a dangling ptr because temporary unique_ptr from make_unique would be destroyed along with the allocated resource
Thus,
if(puter) { std::cout << *puter << std::endl; }
causes undefined behaviors -- You don't know what is there, different compilers and machines can have different results(e.g. can be 50, can be 0, can be nullptr, or some garbage values...)
But the real question is. When should i assume things will get move asigned from temporary? Is there a rule to it? Should i just use release method for assurance in such cases?
It depends if the type/class support move semantics(i.e. have move constructor/move assignment operator defined). If not, it's the same as copying.
In this case, int* is a primitive type, and primitive types do not have move constructor/assignment, so assign a temporary will not be move assign.
On the other hand, if you assign a temporary std::vector to another std::vector, move assignment will be called because std::vector class has a well-defined move assignment operator(and a move constructor). e.g.
std::vector<int> v;
v = std::vector<int>{1,2,3}; //RHS is a temporary object, so it will call the vector's move assignment operator
I accidentally found this issue on C++, but totally had no idea how it was happened, please check the code snippet below:
int main() {
int *aptr = new int(20); //Declare an integer space with 20, and aptr points to it
shared_ptr<int> a(aptr); //Declare a shared_ptr to points where aptr points
stringstream ss;
ss << a;
const char *chstr = ss.str().c_str(); // Save the address as string
void *address;
sscanf(chstr, "%p", (void **)&address); // Convert string back to pointer
a = NULL; // Free the shared pointer
cout << *reinterpret_cast<int*>(address) << endl; // Output: 0, 20 has gone
return 0;
}
Is there anybody could tell me why the address has been freed ?
I didn't manipulate the original integer pointer "aptr", but somehow it's space has disappeared, because of the shared_ptr ?
I'd like to know how it was happend, thank you all !
The whole purpose behind std::shared_ptr is to take ownership of the dynamically-allocated object. Once std::shared_ptr takes ownership of a dynamically-allocated object, via either std::make_shared or by directly assigning a pointer to it, std::shared_ptr owns it, lock stock and barrel. Owning it means automatically deleteing the dynamically scoped object when the last reference to the dynamically-scoped object goes out of scope. That's what the shared_ptr is for, and nothing else.
a = NULL;
This used shared_ptr's assignment operator to replace the shared_ptr-owned pointer(*). Since the original dynamically-scoped object that the shared_ptr owns has no other reference, the shared_ptr deletes the original pointer that was used to construct it.
The fact that you still have the original, native pointer to the int is irrelevant. shared_ptr doesn't care. The whole thing gets deleted.
If you don't want shared_ptr to delete whatever you newed, and use a native pointer for, either don't use shared_ptr, or make sure one is still around as long as you still need to use a native pointer to the underlying object.
(*) This actually implicitly constructs another shared_ptr, and uses the regular assignment operator.
This code does not compile in g++ 4.2.1 (but as Sam mentioned, it complies with version 6):
Georgioss-MacBook-Pro:~ gsamaras$ g++ -Wall main.cpp
main.cpp:17:11: error: no viable overloaded '='
a = NULL; // Free the shared pointer
~ ^ ~~~~
By the way, you should use shared_ptr::reset:
In all other cases, the shared_ptr acquires ownership of p with a use
count of 1, and -optionally- with del and/or alloc as deleter and
allocator, respectively.
Additionally, a call to this function has the same side effects as if
shared_ptr's destructor was called before its value changed (including
the deletion of the managed object if this shared_ptr was unique).
Also check string::c_str. You are saving the address of a temporary string, which is the start of something bad.
I am trying to get the managed object of an aliased shared pointer. My idea was using a weak pointer. Since weak pointers doesn't yield any objects I thought creating a weak pointer from a shared pointer would make the weak pointer forget the stored object of the aliased shared pointer and hence locking the weak pointer would yield a shared pointer with the equal stored and managed pointers. But the results I got confuse me. Does the weak pointer remember from what share pointer is constructed? And is there a way how to get the managed object of an aliased shared pointer?
template<class T> struct Deleter {
void operator()(T* p) const {};
};
Deleter<T> d {};
T t1 {};
T* p1 = &t1;
T t2 {};
T* p2 = &t2;
auto sp1 = std::shared_ptr<T>(p1,d);
auto sp2 = std::shared_ptr<T>(sp1,p2);
auto wp = std::weak_ptr<T>(sp2);
std::cout << sp1.get() << " " << sp2.get() << " " << wp.lock().get() << std::endl;
produce 0x7fff5798c958 0x7fff5798c948 0x7fff5798c948
Does the weak pointer remember from what share pointer is constructed?
It remembers the raw pointer which was stored by the shared_ptr from which it was constructed. I think it would be very confusing if things worked the way you are expecting. For example, if a function recieved a shared_ptr<T> as an argument, it has no idea whether it is aliasing or not. And if that function then wanted to take a weak_ptr from that shared_ptr, it would, I think, be very surprising behavior to find that actualizing that weak_ptr to a shared_ptr gave a completely different object than the original shared_ptr from which it was obtained.
Also note that the aliasing shared_ptr can store a different type than the shared_ptr which it is aliasing. The types don't even have to be convertible to/from each other. And a weak_ptr which is constructed from an aliasing shared_ptr gets its stored type from the shared_ptr it was constructed from (or an implicitly convertible type).
The most common use case for an aliasing shared_ptr, I would suspect (even though I've never had need for one), would be to pass around a member of a shared object, and to be sure it stays alive even if the rest of the owned object is no longer needed. So the scenario which you've constructed, where the type of the aliasing shared_ptr is the same as the original, seems like it would be uncommon.
And is there a way how to get the managed object of an aliased shared pointer?
As far as I'm aware, no. Perhaps there should be. If you think this feature would be useful, propose it. https://groups.google.com/a/isocpp.org/forum/?fromgroups#!forum/std-proposals
I understand how to move an object, for example:
int a(5), b(6);
int c(std::move(a)); // move constructor
c = std::move(b); // move assignment
I understand the common implementation of a custom move constructor (which takes the ownership of a dynamic pointer and sets the moved-from pointer to nullptr.)
But I haven't found anything about moving a dynamically allocated pointer itself. I need confirmation that the following code is legal:
int *p(new int(42));
int val(std::move(*p));
delete p; // I think this is no longer necessary. Is it?
So, is it allowed to move a dynamic pointer?
std::move does not move anything. It merely casts an l-value reference to an r-value reference.
In the example you give, the pointer p has not moved anywhere.
BTW. please don't deal in raw pointers - use a std::unique_ptr instead.
This allocates memory for an int, initialises the int to the value of 42 and stores the address of that memory in p.
int *p(new int(42));
This casts the int pointed to by p to an int&& and then constructs the int val from that r-value reference. Since int is an integral type, a construction from an r-value (i.e. a move) is equivalent to a copy (this is mandated in the standard)
int val(std::move(*p));
Yes, this is still necessary.
delete p;// i think this is no longer necessary. is it ?
In your second example, your code essentially copy the value of one integer to anther. You are not moving the pointer, you are moving the integer the pointer points to.
int a = 42;
int b = std::move(a);
std::cout << a << " : " << b << std::endl; // prints 42 : 42
Moving an integer is copying them.
Even if you moved the pointer, the value of the pointer of copied:
int* a = new int{42};
int* b = std::move(a);
std::cout << *a << " : " << *b << std::endl; // prints 42 : 42
std::cout << std::boolalpha << (a == b) << std::endl; // prints true
So moving raw pointers are copying them too.
You will still need to delete the p pointer.
For every new, there's a delete.
If you don't want to delete it yourself, consider std::unique_ptr, which is aware about move semantics.
Built-in type such as raw pointer, int, floats are not aware of move semantics and moving them will simply copying them.
In your example the use of move semantics is trivial, since you are only using primitive types and raw pointers. std::move is really doing nothing.
Move semantics make the difference when your objects belong to a class that supports move operations (move constructor, move assignment, etc...), or interact with other classes/ functions that do so.
Tipically, after you have move from an object (which is not the result of std::move itself, but the result of the subsequent call), the object is still alive and in a valid state, although it has been deprived of any managed content. Distruction of the objects still remains to be done, it's still a living object.
Note that you rarely see move semantics with raw pointers. It is common to see it with automatic storage objects, or smart pointers. And that's just because is the scenario where move semantics play well with.