Passing std::unique_ptr to constructor to take ownership - c++

I want to pass a std::unique_ptr to the constructor of a class that will take ownership of the data owned by the std::unique_ptr.
Are there any differences between the approaches foo and bar below in terms of how the compiler handles them that would make one of them preferable?
foo class:
template <class T>
class foo
{
std::unique_ptr<T> data_;
public:
foo(std::unique_ptr<T>&& data) :
data_{ std::forward<std::unique_ptr<T>>(data) }
{
}
};
bar class:
template <class T>
class bar
{
std::unique_ptr<T> data_;
public:
bar(std::unique_ptr<T> data) :
data_{ std::move(data) }
{
}
};

Binding to a reference requires one less move:
void f(std::unique_ptr<T>&& p) { g(std::move(p)); }
f(std::make_unique<T>()); // no move, g binds directly to the temporary
Binding to an object parameter requires one actual move:
void f(std::unique_ptr<T> p) { g(std::move(p)); }
f(std::make_unique<T>()); // p constructed (= moved) from temporary,
// g binds to p
The extra move involves one pointer copy, one setting of a pointer to null, and one destructor with a condition check. This is not a big cost, and the question of which style to use depends on the kind of code you're writing:
The more leaf your code is and the less it is used, the more the simple version with by-value passing buys you simplicity. Conversely, the more library your code is and the less you know your users, the more there is value in not imposing avoidable cost, no matter how small.
You decide.

Related

C++ code duplication in classes with both move and copy constructors

For example, a class with two constructors, one taking a reference and the other taking a string r-value reference.
class A {
public:
A(std::string&& str) {
Foo foo(std::move(str));
//do something with foo. (e.g., use it to initialize some members)
field = foo.bar();
}
A(const std::string& str) {
Foo foo(str);
//do something with foo. (e.g., use it to initialize some members)
field = foo.bar();
}
};
If these two constructors perform virtually the same thing besides std::move appearing in the move constructor, is there any way to avoid having two nearly identical chunks of code?
The first option is to use templated constructor:
class A
{
public:
template<typename T, typename = std::enable_if<std::is_same<std::remove_reference<T>::type, std::string>::value>::type>
A(T && str) {
Foo foo(std::forward<T>(str));
//do something
}
};
But it looks a bit ugly. If Foo(const std::string &) actually makes a copy of string, then I'd prefer to pass the parameter by value:
class A
{
public:
A(std::string str) {
Foo foo(std::move(str));
//do something
}
};
The overhead of this approach is additional move constructor.
But don't be bothered of it because the compiler is likely to optimize it.
Accept by value. That will do the trick of doing the same thing as both.
Obvious answer: make a third fn which performs the common part, which is called from both the other fns.
You may be able to directly call one from the other, but it would depend on the nature of the data stored within the class and what is being referenced. However, in many cases a copy constructor can be used to implement move, if desired, though not as efficiently.
You can do this using universal references, but only in the cases where the constructor is templated.
class A {
public:
template<typename T>
A(T && str) {
Foo foo(std::forward<T>(str));
//do something
}
};

Return std::unique_ptr<T> from factory function creating fully hidden implementation of pure virtual interface

I was reading the Smart Pointer Programming Techniques provided in the boost documentation.
In the Section "using abstract classes for implementation hiding", they provide a nice idiom to fully hide an implementation behind pure virtual interface. For example:
// Foo.hpp
#include <memory>
class Foo {
public:
virtual void Execute() const = 0;
protected:
~Foo() = default;
};
std::shared_ptr<const Foo> MakeFoo();
and
// Foo.cpp
#include "Foo.hpp"
#include <iostream>
class FooImp final
: public Foo {
public:
FooImp() = default;
FooImp(const FooImp&) = delete;
FooImp& operator=(const FooImp&) = delete;
void Execute() const override {
std::cout << "Foo::Execute()" << std::endl;
}
};
std::shared_ptr<const Foo> MakeFoo() {
return std::make_shared<const FooImp>();
}
Regarding the protected, non-virtual destructor in class Foo, the document states:
Note the protected and nonvirtual destructor in the example above. The
client code cannot, and does not need to, delete a pointer to X; the
shared_ptr<X> instance returned from createX will correctly call
~X_impl.
which I believe I understand.
Now, it seems to me that this nice idiom could be used to produce a singleton-like entity if a factory function returned std::unique_ptr<Foo>; the user would be forced to move the pointer, with a compile-time guarantee that no copies exist.
But, alas, I cannot make the code work unless I change ~Foo() = default from protected to public, and I do not understand why.
In other words, this does not work:
std::unique_ptr<const Foo> MakeUniqueFoo() {
return std::make_unique<const FooImp>();
}
My questions:
Could you explain me why do I need to make public ~Foo() = default?
Would it be dangerous to just remove protected?
Is the singleton-like idea even worth it?
The issue has to do with how deleters work in smart pointers.
In shared_ptr, the deleter is dynamic. When you have std::make_shared<const FooImp>();, the deleter in that object will call ~FooImpl() directly:
The object is destroyed using delete-expression or a custom deleter that is supplied to shared_ptr during construction.
That deleter will be copied onto the shared_ptr<const Foo> when it's created.
In unique_ptr, the deleter is part of the type. It's:
template<
class T,
class Deleter = std::default_delete<T>
> class unique_ptr;
So when you have unique_ptr<const Foo>, that will call ~Foo() directly - which is impossible since ~Foo() is protected. That's why when you make Foo() public, it works. Works, as in, compiles. You would have to make it virtual too - otherwise you'd have undefined behavior by only destructing the Foo part of FooImpl.
It's not dangerous. Unless you forget to make the destructor virtual, which, it bears repeating, will cause undefined behavior.
This isn't really singleton-like. As to whether or not it's worth it? Primarily opinion based.
Every shared_ptr stores 4 things: a pointer, a strong reference count, a weak reference count, and a deleter.
The deleter gets the type from which the shared_ptr was constructed from, and deletes that type, not the exposed type. If you cast it to a base shared_ptr, the derived deleter is still stored.
unique_ptr does not, by default, store such a stateful deleter.
The design reason behind this is that a shared_ptr is already managing extra resources: adding that deleter is cheap, given that you are already managing the reference counts.
For unique_ptr, without a stateful deleter, the overhead for it is basically identical to a raw pointer. Adding a stateful deleter by default would make unique_ptrs significantly more expensive.
While they are both smart pointers, unique_ptr is really minimal, while shared_ptr is far more complex.
You can get around this by appending a stateful deleter to unique_ptr.
struct stateful_delete {
void const* ptr = nullptr;
void(*f)(void const*) = nullptr;
template<class T>
stateful_delete(T const* t):
ptr(t),
f([](void const* ptr){
delete static_cast<T const*>(ptr);
})
{}
template<class T>
void operator()(T*)const{
if (f) f(ptr);
}
};
template<class T>
using unique_ptr_2 = std::unique_ptr<T, stateful_delete>;
template<class T>
unique_ptr_2<T> unique_wrap_2(T* t) {
return {t, t};
}
template<class T, class...Args>
unique_ptr_2<T> make_unique_2(Args&&...args) {
return unique_wrap( new T(std::forward<Args>(args)...) );
}
such unique_ptr_2 are 3 times as large as a unique_ptr. They do not do an extra allocation (unlike shared_ptr). And they will work with your non-virtual protected ~Foo with a public ~FooImpl.
You could reduce the size of unique_ptr_2 down to 2 pointers if we use the make_shared technique of doing a unified allocation, and store the equivalent of the ptr and f on the heap. I'm uncertain if that complexity is worth the savings.
Based on Barry's answer an alternative to making it public is defining your own deleter which has access to your class' ~Foo() method.
Example (tried with VS2013):
template <typename T>
class deleter
{
public:
void operator()(T* a)
{
// Explicitly call the destructor on a.
a->~A();
}
};
class A {
friend class deleter<A>; // Grant access to the deleter.
protected:
~A() {
// Destructor.
}
};
std::unique_ptr<A, deleter<A>> MakeA()
{
return std::unique_ptr<A, deleter<A>>(new A());
}

unique_ptr, custom deleter, and Rule of Zero

I am writing a class that uses two objects created using a C interface. The objects look like:
typedef struct... foo_t;
foo_t* create_foo(int, double, whatever );
void delete_foo(foo_t* );
(similarly for bar_t). Because C++11, I want to wrap these in a smart pointer so I don't have to write any of the special methods. The class will have unique ownership of the two objects, so unique_ptr logically make sense... but I would still have to write a constructor:
template <typename T>
using unique_ptr_deleter = std::unique_ptr<T, void(*)(T*)>;
struct MyClass {
unique_ptr_deleter<foo_t> foo_;
unique_ptr_deleter<bar_t> bar_;
MyClass()
: foo_{nullptr, delete_foo}
, bar_{nullptr, delete_bar}
{ }
~MyClass() = default;
void create(int x, double y, whatever z) {
foo_.reset(create_foo(x, y, z));
bar_.reset(create_bar(x, y, z));
};
On the flip side, with shared_ptr, I wouldn't have to write a constructor, or use a type alias, since I could just pass in delete_foo into reset() - although that would make my MyClass copyable and I don't want that.
What is the correct way to write MyClass using unique_ptr semantics and still adhere to Rule of Zero?
Your class doesn't need to declare a destructor (it will get the correct default implementation whether or not you declare it defaulted), so still obeys the "Rule of Zero".
However, you might improve this by making the deleters function objects, rather than pointers:
template <typename T> struct deleter;
template <> struct deleter<foo_t> {
void operator()(foo_t * foo){delete_foo(foo);}
};
template <> struct deleter<bar_t> {
void operator()(bar_t * bar){delete_bar(bar);}
};
template <typename T>
using unique_ptr_deleter = std::unique_ptr<T, deleter<T>>;
This has a few benefits:
the unique_ptr doesn't need to store an extra pointer
the delete function can be called directly, rather than via a pointer
you don't need to write a constructor; the default constructor will do the right thing.

What is the virtual function inside of shared_ptr's Control Block?

I've read an "Item" about shared_ptr in Scott Meyers' book "Effective Modern C++" where he says the following:
The usual control block implementation is more
sophisticated than you might expect. It makes use of inheritance, and there’s even a virtual function. (It’s used to ensure that the pointed-to object is properly destroyed.)
That means that using std::shared_ptrs also incurs the cost of the machinery for the virtual function used by the control block.
Then he doesn't explain what a virtual function does exactly. As far as I know, the proper way of deleting a pointed object is using deleters or type erasure. So, please explain what this is about.
The virtual function is required to ensure the object being shared is appropriately deleted. Unlike a unique_ptr, shared_ptr does not require full knowledge of the type when its template is instantiated. E.g. you can do this:
class Foo;
std::shared_ptr<Foo> foo = make_foo();
Note that in the code above we don't have the complete Foo type, just the forward declaration. If we let foo go out of scope, the object it is pointing to will be correctly deleted because when Foo was created in make_foo, a deleter was also created which knows the complete type of Foo, and hence can call the appropriate destructors. (E.g. Perhaps make_foo creates a Bar that inherits from Foo and returns that. shared_ptr's will handle this fine.)
The function on the deleter object that shared_ptr creates to manage the deletion of Foo will be virtual, allowing shared_ptr to call the correct destructor.
Roughly this could be something like this:
struct deleter_interface {
virtual void ~deleter_interface = default;
virtual void dispose() = 0;
};
template <typename T>
struct deleter : deleter_interface {
T* ptr_;
deleter(T* ptr) : ptr_(ptr) {}
virtual void dispose() { delete ptr_; }
};
template <typename T>
shared_ptr {
T* ptr_;
deleter_interface* deleter_;
...
};
template <typename T>
shared_ptr<T>::shared_ptr<T>(T* ptr)
: ptr_(ptr), deleter_(new deleter<T>(ptr)) {}
template <typename T>
shared_ptr<T>::~shared_ptr<T>() { deleter_->dispose(); delete deleter_; }
While this seems more complicated that is strictly necessary, it is to allow shared_ptr to be used without the complete type. For example what if you wanted to do this:
In a.h:
struct Foo;
std::shared_ptr<Foo> a = make_object();
// ... let a go out of scope
And in a.cc:
struct Foo { ... };
struct Bar : Foo { ... };
std::shared_ptr<Foo> make_object() { return std::shared_ptr<Foo>(new Bar); }
If we didn't have the virtual function used in the deleter code, then Bar would not be destructed correctly. With the virtual function it doesn't matter that the header (a.h) never sees the definition of Foo or Bar.

Nonvirtual deleter with smart pointers

I was reading the latest Overload (link) and decided to test out the statement at page 8:
shared_ptr will properly invoke B’s destructor on scope exit, even
though the destructor of A is not virtual.
I am using Visual Studio 2013, compiler v120:
#include <memory>
#include <iostream>
struct A {
~A() { std::cout << "Deleting A"; }
};
struct B : public A
{
~B() { std::cout << "Deleting B"; }
};
int main()
{
std::shared_ptr<A> ptr = std::make_shared<B>();
ptr.reset();
return 0;
}
This works as expected and prints out "Deleting BDeleting A"
The article seems to imply that this should also work with std::unique_ptr:
There is almost no need to manage your own resources so resist the
temptation to implement your own copy/assign/move construct/move
assign/destructor functions.
Managed resources can be resources inside
your class definition or instances of your classes themselves.
Refactoring the code around standard containers and class templates
like unique_ptr or shared_ptr will make your code more readable and
maintainable.
However, when changing
std::shared_ptr<A> ptr = std::make_shared<B>();
to
std::unique_ptr<A> ptr = std::make_unique<B>();
the program will only output "Deleting A"
Did I misunderstand the article and the behavior is intended by the standard?
Is it a bug with the MSVC compiler?
shared_ptr and unique_ptr are different. make_shared will create a type erased deleter object on invocation while with unique_ptr the deleter is part of the type. Therefore the shared_ptr knows the real type when it invokes the deleter but the unique_ptr doesn't. This makes unique_ptr's much more efficient which is why it was implemented this way.
I find the article a bit misleading actually. I do not consider it to be good advice to expose copy constructors of a base class with virtual functions, sounds like a lot of slicing problems to me.
Consider the following situation:
struct A{
virtual void foo(){ std::cout << "base"; };
};
struct B : A{
virtual void foo(){ std::cout << "derived"; };
};
void bar(A& a){
a.foo(); //derived
auto localA = a; //poor matanance porgrammer didn't notice that a is polymorphic
localA.foo(); //base
}
I would personally advocate non-intrusive polymorphism http://isocpp.org/blog/2012/12/value-semantics-and-concepts-based-polymorphism-sean-parent for any new higherarchies, it sidesteps the problem entirely.
This behaviour is according to the standard.
The unique_ptr is designed to have no performance overhead compared to the ordinary new/delete.
The shared_ptr has the allowance to have the overhead, so it can be smarter.
According to the standard [20.7.1.2.2, 20.7.2.2.2], the unique_ptr calls delete on the pointer returned by get(), while the shared_ptr deletes the real object it holds - it remembers the proper type to delete (if properly initialized), even without a virtual destructor.
Obviously, the shared_ptr is not all-knowing, you can trick it to behave badly by passing a pointer to the base object like this:
std::shared_ptr<Base> c = std::shared_ptr<Base> { (Base*) new Child() };
But, that would be a silly thing to do anyhow.
You could do something similar with unique_ptr, but since its deleter type is determined statically, you need to statically maintain the proper deleter type. i.e. (Live demo at Coliru):
// Convert given pointer type to T and delete.
template <typename T>
struct deleter {
template <typename U>
void operator () (U* ptr) const {
if (ptr) {
delete static_cast<T*>(ptr);
}
}
};
// Create a unique_ptr with statically encoded deleter type.
template <typename T, typename...Args>
inline std::unique_ptr<T, deleter<T>>
make_unique_with_deleter(Args&&...args) {
return std::unique_ptr<T, deleter<T>>{
new T(std::forward<Args>(args)...)
};
}
// Convert a unique_ptr with statically encoded deleter to
// a pointer to different type while maintaining the
// statically encoded deleter.
template <typename T, typename U, typename W>
inline std::unique_ptr<T, deleter<W>>
unique_with_deleter_cast(std::unique_ptr<U, deleter<W>> ptr) {
T* t_ptr{ptr.release()};
return std::unique_ptr<T, deleter<W>>{t_ptr};
}
// Create a unique_ptr to T with statically encoded
// deleter for type U.
template <typename T, typename U, typename...Args>
inline std::unique_ptr<T, deleter<U>>
make_unique_with_deleter(Args&&...args) {
return unique_with_deleter_cast<T>(
make_unique_with_deleter<U>(std::forward<Args>(args)...)
);
}
It's a bit awkward to use:
std::unique_ptr<A, deleter<B>> foo = make_unique_with_deleter<A, B>();
auto improves the situation:
auto bar = make_unique_with_deleter<A, B>();
It doesn't really buy you much, since the dynamic type is encoded right there in the static type of the unique_ptr. If you're going to carry the dynamic type around, why not simply use unique_ptr<dynamic_type>? I conjecture such a thing may have some use in generic code, but finding an example of such is left as an exercise to the reader.
The technique std::shared_ptr employs to do the magic is called type erasure. If you are using gcc, try to find the file bits/shared_ptr_base.h and check the implementation. I'm using gcc 4.7.2.
unique_ptr is designed for minimum overhead and does not use type erasure to remember the actual type of the pointer it holds.
Here is a great discussion on this topic: link
EDIT: a simple implementation of shared_ptr to showcase how type erasure is achieved.
#include <cstddef>
// A base class which does not know the type of the pointer tracking
class ref_counter_base
{
public:
ref_counter_base() : counter_(1) {}
virtual ~ref_counter_base() {}
void increase()
{
++counter_;
}
void release()
{
if (--counter_ == 0) {
destroy();
delete this;
}
}
virtual void destroy() = 0;
private:
std::size_t counter_;
};
// The derived class that actually remembers the type of
// the pointer and deletes the pointer on destroy.
template <typename T>
class ref_counter : public ref_counter_base
{
public:
ref_counter(T *p) : p_(p) {}
virtual void destroy()
{
delete p_;
}
private:
T *p_;
};
template <typename T>
class shared_ptr
{
public:
shared_ptr(T *p)
: p_(p)
, counter_(new ref_counter<T>(p))
{
}
// Y* should be implicitely convertable to T*,
// i.e. Y is derived from T
template <typename Y>
shared_ptr(Y &other)
: p_(other.get())
, counter_(other.counter())
{
counter_->increase();
}
~shared_ptr()
{
counter_->release();
}
T* get() { return p_; }
ref_counter_base* counter() { return counter_; }
private:
T *p_;
ref_counter_base *counter_;
};