is std::move() the same as using reset() and release() together? [duplicate] - c++

For std::unique_ptrs p1 and p2, what are differences between std::move() and std::unique_ptr::reset()?
p1 = std::move(p2);
p1.reset(p2.release());

The answer should be obvious from the standard's specification of move assignment in [unique.ptr.single.assign]/2:
Effects: Transfers ownership from u to *this as if by calling reset(u.release()) followed by an assignment from std::forward<D>(u.get_deleter()).
Clearly move assignment is not the same as reset(u.release()) because it does something additional.
The additional effect is important, without it you can get undefined behaviour with custom deleters:
#include <cstdlib>
#include <memory>
struct deleter
{
bool use_free;
template<typename T>
void operator()(T* p) const
{
if (use_free)
{
p->~T();
std::free(p);
}
else
delete p;
}
};
int main()
{
std::unique_ptr<int, deleter> p1((int*)std::malloc(sizeof(int)), deleter{true});
std::unique_ptr<int, deleter> p2;
std::unique_ptr<int, deleter> p3;
p2 = std::move(p1); // OK
p3.reset(p2.release()); // UNDEFINED BEHAVIOUR!
}

The first one is capable of warning you if there is a destructor mismatch, for example. In addition, release() is a very dangerous function, and your trivial example is correct but many other uses are not. It's best to simply never, ever use this function.

The second version might not be exception safe, I think. It is equivalent to:
auto __tmp = p2.release();
p1.reset(__tmp);
Thus if the call to std::unique_ptr::reset throws (which may be the case if the deletion of the managed object throws), then you have an unreferred object which won't get destroyed ever. In case of the move assignment, the std::unique_ptr can (and should) wait with the actual move until p1's original object has been destroyed properly.
But note, that this is only a problem if the destructor of the managed object could throw, which is in nearly all cases wrong in itself, or if you use a custom deleter which might throw. So in practice there isn't usually any behavioural difference between the two code snippets.
EDIT: In the end Jonathan points out in his comment, that the custom deleter is required by the standard not to throw, which indeed makes the throwing of std::unique_ptr::reset pretty unlikely/non-conformant. But he also points out that there is another difference, in that only a move assignment also moves any custom deleters, which he has also written an answer for.
But disregarding actual resulting behaviour, there is a huge conceptual difference between the two. If a move assignment is appropriate, then do a move assignment and try not to emulate it by some other code. In fact I cannot image any reason to replace the first code snippet one-to-one by the second. DeadMG is right in that std::unique_ptr::release should only be used if you really know what you're doing and in which context you're messing with unmanaged dynamic objects.

Related

Why do unique_ptr have two functions reset and operator= that do similar things but not overload?

I know this may sound like a strange question, but I'm very curious.
unique_ptr operator= takes an r-value reference as a parameter and calls reset(r.release()), then move custom deleter. finally, operator returns *this. like:
// this is pseudo code
unique_ptr& operator=(unique_ptr&& r)
{
reset(r.release()); // Change managed pointer
setDeleter(r.getDeleter());
return *this;
}
unique_ptr reset function takes l-value raw pointer as a parameter and delete the old pointer after changing the pointer it manages.
Between the two, they have the same behavior of changing the pointer being managed. And that behavior is handled by the same reset() function.
These two functions do similar things, and I couldn't think of a separate use case other than the difference in parameters, so I wondered if it might be possible to overload them. like:
// this is pseudo code
unique_ptr& operator=(unique_ptr&& r) // or a function named reset
{
changeManagedPtr(r.release()); // and delete old pointer
setDeleter(r.getDeleter());
return *this;
}
unique_ptr& operator=(pointer p) // or a function named reset
{
changeManagedPtr(p); // and delete old pointer
// setDeleter(r.getDeleter()); there is no deleter in p
return *this;
}
Why are the two functions written separately and not as overloaded functions with the same name?
If it were possible, wouldn't it be possible to use something less confusing like this:
unique_ptr<int> uniqPtrInt, dest;
int* rawPtrInt = new int;
dest = rawPtrInt;
// some work..
dest = uniqPtrInt;
Am I assuming something wrong? Are there any stability ramifications that I'm not aware of?
unique_ptr& unique_ptr::operator=(pointer p) can be implemented, but the committee chose not to, for the same reason that they made unique_ptr::unique_ptr(pointer p) explicit.
A unique pointer represents unique ownership of an object. If you could implicitly construct or assign them from raw pointers, it would be very easy to accidentally transfer ownership (and, not realising that you have, do something with undefined behaviour, like double delete).
The assignment semantics of std::unique_ptr is move-only, i.e. move assignment. Adding onto that an opaque copy-assignment-looking from pointer which moves under the hood would arguably risk leading to confusion, and std::unique_ptr was designed with safety in mind ("make it hard to misuse"). That rejects the idea of overloading the assignment operator with a pointer overload.
Over to reset(): whilst reset() could arguably also provide an overload to replace the managed object of *this with that of a std::unique_ptr overload, it would mean adding to the API of std::unique_ptr another way of essentially performing move-assignment, an operation where move-assignment op should be favored (semantically).

Using make_shared with emplace_back and push_back - any difference?

some_vector.push_back(make_shared<ClassName>());
some_vector.emplace_back(make_shared<ClassName>());
I want to check that my understanding is correct that for make_shared and in general for all other functions that returns an object those two calls are identical. Here make_shared will create a new shared_ptr, and then this pointer will be moved into the container both in push_back and emplace_back. Is this correct, or will there be some difference?
vector<T>::push_back has a T&& overload, which does the same as the vector<T>::emplace_back T&& version.
The difference is that emplace_back will perfect-forward any set of arguments to the T's constructor, while push_back only takes T&& or T const&. When you actually pass a T&& or T const& the standard specification of their behaviour is the same.
I want to add a small detail to Yakk's answer.
The forwarding of arguments for the emplace_back-case can introduce horrible bugs in doubt - even for vectors of shared pointers - if not used with special care, see for instance
#include <vector>
#include <memory>
struct SimpleStruct {};
auto main() -> int
{
std::vector<std::shared_ptr<SimpleStruct>> v;
SimpleStruct a;
v.emplace_back(std::addressof(a)); // compiles, UB
v.push_back(std::addressof(a)); // fails to compile
}
Yes, that's a kind of an extreme example since code like this should always be used with special care or questioned in general, but it emphasizes, that one should only refer to emplace_back if one hasn't the to copy object already at hands and its only purpose is to be added to the vector, and refer to push_back for all common copy/move-construction cases. It would be nice if the language/standard library could force that from scratch for emplace_back, i.e. only accepting the custom non-copy/move constructors in order to have this clear separation but even if it's possible in an acceptable way, it would be in conflict with many template-context scenarios (fast-forwarding) and the error-prone usage is still possible, although a bit more explicit.
According to my example from above, code refactorization is an important point here in doubt. Simply imagine that the previous code used raw pointers, i.e. the actual underlying bug was already persistent there and hidden by emplace_back -usage. It would also had been hidden by push_back -usage there but not as soon as you update your code to the shared pointer way.
Even if it's not relevant for your particular specific use-case, I think it's worth to be mentioned here since one should be totally confident about the underlying differences between both methods.
Thanks to Human-Compiler in the comments for mentioning my used previous wrong terminology here.
To understand this problem let's first consider what would be the result of calling std::make_shared<class_type>(),
It returns temporary object which means Xvalue an eXpiring value whose resources can be reused. Now let's see both cases,
some_vector.push_back(make_shared<ClassName>());
std::vector have two overload of push_back and one of them accept rvalue reference that isconstexpr void push_back( T&& value );
It means value is moved into new element, but how? rvalue overload of push_back will move construct new value by invoking shared_ptr( shared_ptr&& r ) noexcept; and ownership of r will be taken and r become empty.
some_vector.emplace_back(make_shared<ClassName>());
In emplace_back( Args&&... args ) element is constructed through std::allocator_traits::construct by perfect forwarding args.. through std::forward<Args>(args)..., It means rvalue will perfect forward and cause same move constructor shared_ptr( shared_ptr&& r ) noexcept; to be invoked.
Conclusion is, both push_back and emplace_back have same effect.
But what is explained above doesn't happen because compiler comes into the picture and what it does, it perform optimization, It means rather than creating temporary objects and moving them into other objects, it directly creates objects in place.
Again result is same in both cases.
Below, supporting code for compiler optimization theory is included and as you can see output only prints one constructor call.
#include <iostream>
using std::cout;
using std::endl;
class Object{
public:
explicit Object(int );
Object(const Object& );
Object(Object&& );
};
Object::Object(int ){
cout<< __PRETTY_FUNCTION__<< endl;
}
Object::Object(const Object& ){
cout<< __PRETTY_FUNCTION__<< endl;
}
Object::Object(Object&& ){
cout<< __PRETTY_FUNCTION__<< endl;
}
int main(){
[[maybe_unused]] Object obj(Object(1));
}
Output:
Object::Object(int)
some_vector.push_back(make_shared<ClassName>()); rvalue reference is passed to the function, the push_back simply calls emplace_back.
void push_back(value_type&& __x)
{ emplace_back(std::move(__x)); }

Is *this = Ctor(); legal and efficient for clearing an object's state?

I've stumbled across this piece of code to reestablish class invariants:
class Foo {
// some stuff in here
public:
void clear() {
*this = Foo();
//operator=(Foo()); // commented out in favor of the line above
}
};
I would assume that the call to operator= is legal and works as expected, but will create an unnecessary temporary, in case the class is not movable. So it would probably be more efficient to manually assign default values, which is cumbersome and error-prone if we want to extend the class.
*this = Foo(), if allowed, is probably more efficient, as copy elision could work here I assume (regardless of the class being movable).
So my questions are:
Is the statement *this = Foo(); legal? If yes, please provide a reference to the standard
What is more efficient (providing that the first bullet point is true)?
In case Foo is movable.
In case it's not.
Is the statement *this = Foo(); legal? If yes, please provide a reference to the standard
That's legal yes. It follows the standard that the value can be assigned through a dereferenced pointer.
I don't think we can find anything in the c++-standard mentioning the situation, since it's not a special situation as you think it is.
Assigning a dereferenced *this pointer works as with any other pointer.
What is more efficient (providing that the first bullet point is true)?
In case Foo is movable.
In case it's not.
There are no differences regarding efficiency. Copy elision will be taken by any decent modern c++ compiler.

why should we use std::move semantic with unique pointers?

Conceptual Question
Say we have simple example like this:
void foo(std::unique_ptr<int> ptr)
{
std::cout << *ptr.get() << std::endl;
}
int main()
{
std::unique_ptr<int> uobj = std::make_unique<int>(4);
foo(uobj ); // line-(1) Problem ,but Alternative -> foo(std::move(uobj ))
std::unique_ptr<int> uobjAlt = uobj; // line-(2) Problem ,but Alternative -> std::unique_ptr<int> uobjAlt = std::move(uobj);
return EXIT_SUCCESS;
}
We know simply std::unique_ptr bound with concept of resource owning by single owner with moving resource among multiple owners while shared_ptr has opposite aspect.
As example shown above, when you look at line-(1) & line-(2) you notice that some standard rules are being violated because std::unique_ptr has(deleted) no both copy constructors and copy assignable operators defined, but In order to avoid compilation errors we have to use std::move function instead.
Problem
Why modern C++ compiler cannot automatically generate instructions to move the resource among unique pointers in line-(1) and line-(2)? because we know unique pointer intentionally design for that. Why should we use std::move explicitly to instruct the machine to move ownership of the resource?
std::unique_ptr nothing but class template.we know that, But situations addressed in line-1 and line -2 having issues while compiler complain about copying unique_pointers not allowed(deleted functions).why we having these kind of errors why c++ standard and compiler vendors cannot override this concept?
Unique Pointer intentionally designed for the purpose of moving resource while passing its ownership, when we pass it as function/constructor argument or assign to another unique pointer, it conceptually should move resource with ownership nothing else, but why we should use std::move to convey compiler to actual move, why don't we have a freedom to call line-(1) and line-(2) as it is? (while intelligent compiler generate automatic move operation among unique pointers for us, unless there is const or non-const reference passing).
(Sorry for long description and broken English) Thank you.
unique_ptr is useful to free memory for you automatically when uobj goes out of scope. That's its job. So, since it has 1 pointer it has to free, it has to be unique, and hence its name: unique_ptr!
When you do something like this:
std::unique_ptr<int> uobjAlt = uobj;
You're issuing a copy operation, but, you're not supposed to copy the pointer, because copying means that both objects uobjAlt and uobj must both be freed, which will directly lead to a segmentation fault and a crash. So, by using std::move, you're moving ownership from one object to another.
If you want to have multiple pointers to a single object, you should consider using std::shared_ptr.
This has nothing to do with whether the compiler can do this. It certainly could work that way, and in fact, it did work that way prior to C++11 with std::auto_ptr<>. It was horrible.
std::auto_ptr<int> x = std::auto_ptr<int>(new int(5));
std::auto_ptr<int> y = x;
// Now, x is NULL
The problem here is that the = sign usually means "copy from x to y", but in this case what is happening is "move from x to y, invalidating x in the process". Yes, if you are a savvy programmer you would understand what is going on here and it wouldn't surprise you, at least not all of the time. However, in more common situations it would be horribly surprising:
Here's MyClass.h:
class MyClass {
private:
std::auto_ptr<Type> my_field;
...
};
Here's MyClass.cpp:
void MyClass::Method() {
SomeFunction(my_field);
OtherFunction(my_field);
}
Here's Functions.h:
// Which overload, hmm?
void SomeFunction(Type &x);
void SomeFunction(std::auto_ptr<Type> x);
void OtherFunction(const std::auto_ptr<Type> &x);
Now you have to look at three different files before you can figure out that my_field is set to NULL. With std::unique_ptr you only have to look at one:
void MyClass::Method() {
SomeFunction(std::move(my_field));
OtherFunction(my_field);
}
Just looking at this one function I know that it's wrong, I don't have to figure out which overload is being used for SomeFunction, and I don't have to know what the type of my_field is. There's definitely a balance that we need to have between making things explicit and implicit. In this case, the fact that you couldn't explicitly tell the difference between moving and copying a value in C++ was such a problem that rvalue references, std::move, std::unique_ptr, etc. were added to C++ to clear things up, and they're pretty amazing.
The other reason why auto_ptr was so bad is because it interacted poorly with containers.
// This was a recipe for disaster
std::vector<std::auto_ptr<Type> > my_vector;
In general, many templates worked poorly with auto_ptr, not just containers.
If the compiler were allowed to auto-infer move semantics for types such as std::unique_ptr, code like this would break:
template<typename T> void simple_swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
The above counts on tmp being a copy of a (because it continues to use a as the left-hand side of as assignment operator). There is code in the standard algorithms which actually requires temporary copies of container values. Inferring moves would break them, causing crashes at run-time. This is why std::auto_ptr was warned against ever being used in STL containers.

Pointer container class which can't be copied by value

I need a smart pointer for my project which can be send to several methods as parameter. I have checked auto_ptr and shared_ptr from boost. But IMO, that is not suitable for my requirements. Following are my findings
auto_ptr : When passed to another method, ownership will be transferred and underlying pointer will get deleted when that method's scope ends. We can workaround this by passing auto_ptr by reference, but there is no compile time mechanism to ensure it is always passed by reference. If by mistake, user forgot to pass a reference, it will make problems.
boost::shared_ptr : This looks promising and works correctly for my need. But I feel this is overkill for my project as it is a very small one.
So I decided to write a trivial templated pointer container class which can't be copied by value and take care about deleting the underlying pointer. Here it is
template <typename T>
class simple_ptr{
public:
simple_ptr(T* t){
pointer = t;
}
~simple_ptr(){
delete pointer;
}
T* operator->(){
return pointer;
}
private:
T* pointer;
simple_ptr(const simple_ptr<T>& t);
};
Is this implementation correct? I have made copy constructor as private, so that compiler will alert when someone tries to pass it by value.
If by chance the pointer is deleted, delete operation on the destructor will throw assertion error. How can I workaround this?
I am pretty new to C++ and your suggestion are much appreciated.
Thanks
Please use boost::scoped_ptr<> as suggested by Martin York, because it:
Does exactly what you want (it's a noncopyable pointer)
Has no overhead above that of a standard C pointer
Has been carefully crafted by super-intelligent C++ wizards to make sure it behaves as expected.
While I can't see any problems with your implementation (after applying the changes suggested by ChrisW), C++ has many dark corners and I would not be surprised if there is some obscure corner case which you, I and the others here have failed to spot.
What you have done is boost::scoped_ptr
Please also read comment by j_random_hacker.
Is this implementation correct? I have made copy constructor as private ...
You could do the same for the assignment operator:
simple_ptr& operator=(const simple_ptr<T>& t);
A const version of the dereference operator might be useful too, and, smart pointers usually define the other kind of dereference operator as well:
const T* operator->() const { return pointer; }
const T& operator*() const { return *pointer; }
T& operator*() { return *pointer; }
If by chance the pointer is deleted, delete operation on the destructor will throw assertion error. How can I workaround this?
Do you mean, if I do this:
//create instance
Car* car = new Car;
//assign to smart ptr
simple_ptr<Car> ptr(car);
//explicit delete
delete car;
//... assertion when ptr is destroyed ...
A way (I don't know if it's a good way) to prevent that is to declare the constructor, and/or the destructor, and/or the delete operator of the T class as private, and say that simple_ptr is a friend of the T class (so that only the simple_ptr class can create and/or destroy and/or delete instances of T).
Marking the new operator as private in T class seems to be impossible as I have to modify all the classes which will be used with simple_ptr
Yes that's true: to do my suggestion immediately above, you would need to modify the class definitions.
If your question is "how can I make double deletes impossible, without modifying class definitions?" then I think the answers are:
You can't: it's up the application code (which uses these classes) to be careful
You can: by providing your own heap manager i.e. your own implementation of global operator new and global operator delete and, in your smart_ptr code, interrogate your heap manager to see whether this incarnation of this pointer is still allocated, before you delete it
To answer your first question, the best assurance you can get that this is correct is to implement a test harness around it to do some simple task, and make sure you get the behavior you expect. For me, that is far better comfort the code is right than the opinion of some random person reading it.
As for your second question, you work around delete throwing an assertion error by setting pointer to some marker value after you delete it the first time. Something like:
if (pointer) {
delete pointer;
pointer = NULL;
} else {
error("Attempted to free already freed pointer.");
}
The problem you're going to run into here is that your overloaded -> operator returns the value of the pointer, which means whoever you return this to can also call delete, causing the check I propose above not to work. For example:
simple_ptr<int> myPtr = someIntPointer;
...
delete myPtr.operator->(); /* poof goes your pointered memory region */
I might recommend that you not rely on the operator-> overloading, and just require that those using this class call a method that dereferences the pointer internally before passing that value back to the user.
Hope this helps.
You should user a boost::scoped_ptr<> as has been mentioned already.
In general though, if you need to make a class non-copyable, you should inherit from boost::noncopyable, i.e.
#include <boost/utility.hpp>
class myclass : boost::noncopyable
{
...
};
This does all the work of making it non-copyable and is nicely self-documenting.
You've got two choices:
boost::scoped_ptr already detailed by j_random_hacker, because it's non-copyable (doesn't share ownership like shared_ptr) and non-movable (doesn't transfer ownership like auto_ptr. auto_ptr has a copy constructor, but that one does not copy. It moves the original pointer to *this). boost::scoped_ptr is exactly what you need.
const auto_ptr doesn't allow transfer of ownership. And take your parameter by reference to const (auto_ptr<T> const&). If the writer of a function accepts by value instead, it still won't work if you try passing a const auto_ptr, because its copy constructor needs a non-const auto_ptr.
Until C++1x, boost::scoped_ptr is the best choice for your needs, or a const auto_ptr if you have to use official standard stuff (read this). In C++1x, you can use std::unique_ptr as a better alternative to auto_ptr, because you have to explicitly state when you want to transfer ownership. Trying to copy it will result in a compile time error. unique_ptr is detailed a little in this answer.
I've seen sometimes usage of simple DISABLE_COPY macros:
#define DISABLE_COPY(Class) \
Class(const Class &); \
Class &operator=(const Class &);
So it's a common practice to define copy constructor and assignment operator as private for your task.