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.
Related
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.
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.
I'm working on implementing a reflection mechanism in C++.
All objects within my code are a subclass of Object(my own generic type) that contain a static member datum of type Class.
class Class{
public:
Class(const std::string &n, Object *(*c)());
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
For any subclass of Object with a static Class member datum, I want to be able to initialize 'create' with a pointer to the constructor of that subclass.
You cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")
Your best bet is to have a factory function/method that creates the Object and pass the address of the factory:
class Object;
class Class{
public:
Class(const std::string &n, Object *(*c)()) : name(n), create(c) {};
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
class Object {};
Object* ObjectFactory()
{
return new Object;
}
int main(int argc, char**argv)
{
Class foo( "myFoo", ObjectFactory);
return 0;
}
I encountered this same problem. My solution was a template function which called the constructor.
template<class T> MyClass* create()
{
return new T;
}
To use this as a function pointer is simple:
MyClass* (*createMyClass)(void) = create<MyClass>;
And to get an instance of MyClass:
MyClass* myClass = createMyClass();
Lambda style:
[](){return new YourClass();}
Using variadic templates you can create a wrapper which will turn the constructor into a functor.
#include <utility>
template <typename T>
struct BindConstructor{
template<typename... Args>
T operator()(Args&&...args)const{
return T(std::forward<Args>(args)...);
}
};
struct Foo {
Foo(int a, int b):a(a),b(b){}
int a;
int b;
};
template <typename Fn>
auto Bar(Fn f){
return f(10,20);
}
int main(){
Foo foo = Bar(BindConstructor<Foo>());
}
https://godbolt.org/z/5W383McTc
Hmm, odd. create is a member variable i.e. only available in class instances but the intent of it seems to be creating an instance in the first place.
You cannot take the address of a constructor, but you can create static factory methods of your own and take the address of that.
You can't use regular function pointers on methods, you have to use method pointers, which have bizarre syntax:
void (MyClass::*method_ptr)(int x, int y);
method_ptr = &MyClass::MyMethod;
This gives you a method pointer to MyClass's method - MyMethod. However this isn't a true pointer in that it's not an absolute memory address, it's basically an offset (more complicated than that due to virtual inheritance, but that stuff is implementation specific) into a class. So to use the method pointer, you have to supply it with a class, like this:
MyClass myclass;
myclass.*method_ptr(x, y);
or
MyClass *myclass = new MyClass;
myclass->*method_ptr(x, y);
Of course it should be obvious at this point that you can't use a method pointer to point to an objects constructor. In order to use a method pointer you need to have an instance of the class so it's constructor has already been called! So in your case Michael's Object Factory suggestion is probably the best way of doing it.
Using Qt, you can call a constructor with Qt reflection mechanisms (QMetaObject) if you declare the constructor as Q_INVOKABLE (nothing more to do than that).
class MyClass : public QObject {
Q_OBJECT
public:
Q_INVOKABLE MyClass(int foo);
MyClass *cloningMySelf() {
return metaObject()->newInstance(Q_ARG(int, 42));
}
};
I'm not sure you will want to embed Qt just for that feature ;-) but maybe you would like to have a look on the way it does that.
http://doc.qt.io/qt-5/metaobjects.html#meta-object-system
If you want an actual function pointer representing the constructor, not a functor or closure, you can create a universal factory template:
#include <iostream>
namespace {
template <typename Type, typename... Args>
Type create(Args... args)
{
return Type{std::forward<Args>(args)...};
}
}
template <typename Type, typename... Args>
static constexpr auto constructor = &create<Type, Args...>;
struct Foo {
Foo(double v){ std::cout << "Foo ctor " << v << std::endl; }
};
int main()
{
auto z = constructor<Foo, double>(0.33);
return 0;
}
Foo ctor 0.33
https://godbolt.org/z/qKGGGzjTs
This is similar to Michael Burr's answer, except that you don't have a static factory method per object and it allows any kind of constructor (not just default)
This is similar to bradgonesurfing's answer, except that you create one function pointer per constructor and not one functor per class representing all constructors for that class.
Even though this question is old and already has several very helpful answers, I am adding this additional suggestion because having one function pointer for every constructor of any class is useful when implementing a runtime type reflection system.
I am making an class which is managed by a unique_ptr, but for various reasons I need to give implementations access to a raw pointer to the object. However I want to ensure that users don't inadvertently delete the underlying object. I have come up with the following example code:
(It is part of a tree structure, and I need to be able to look at members of tree nodes without actually detaching them. shared_ptr seems like overkill in this situation.)
#include <memory>
using namespace std;
class unOnly
{
~unOnly() {}
public:
unOnly() {}
friend class default_delete<unOnly>;
};
int main()
{
unique_ptr<unOnly> ptr(new unOnly());
}
This compiles for me in gcc 4.4.5. However, can I be sure that in all implementations default_delete is what actually deletes the object, as opposed to some private implementation class? Should I write my own deleter to be sure?
Why not
class unOnly
{
unOnly() {}
~unOnly() {}
struct deleter { void operator()(unOnly* x) { delete x; }};
public:
typedef std::unique_ptr<unOnly, deleter> handle;
static handle create() { return handle(new unOnly); }
};
auto x = unOnly::create();
? Or even
class unOnly
{
~unOnly() {}
struct deleter { void operator()(unOnly* x) { delete x; }};
public:
unOnly() {}
typedef std::unique_ptr<unOnly, deleter> handle;
};
unOnly::handle x(new unOnly);
(I prefer the former, but the latter is perhaps more in the spirit of what you're asking for)
The point of unique_ptr (besides having an object which owns it's pointer) is that you can pass it a custom deleter, so it makes sense just to write one instead of doing something else, which seems unnecessarily complex.
Quoting from the standard:
20.7.1 Class template unique_ptr
6. [...]
template<class T, class D = default_delete<T>> class unique_ptr;
20.7.1.1.1
1 The class template default_delete serves as the default deleter (destruction policy) for the class template unique_ptr.
So, it seems implementations of unique_ptr are required to use default_delete as the default deleter.
EDIT:
But this doesn't mean your approach is foolproof, see #RMartinhoFernandes' comment below.
I'm working on implementing a reflection mechanism in C++.
All objects within my code are a subclass of Object(my own generic type) that contain a static member datum of type Class.
class Class{
public:
Class(const std::string &n, Object *(*c)());
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
For any subclass of Object with a static Class member datum, I want to be able to initialize 'create' with a pointer to the constructor of that subclass.
You cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")
Your best bet is to have a factory function/method that creates the Object and pass the address of the factory:
class Object;
class Class{
public:
Class(const std::string &n, Object *(*c)()) : name(n), create(c) {};
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
class Object {};
Object* ObjectFactory()
{
return new Object;
}
int main(int argc, char**argv)
{
Class foo( "myFoo", ObjectFactory);
return 0;
}
I encountered this same problem. My solution was a template function which called the constructor.
template<class T> MyClass* create()
{
return new T;
}
To use this as a function pointer is simple:
MyClass* (*createMyClass)(void) = create<MyClass>;
And to get an instance of MyClass:
MyClass* myClass = createMyClass();
Lambda style:
[](){return new YourClass();}
Using variadic templates you can create a wrapper which will turn the constructor into a functor.
#include <utility>
template <typename T>
struct BindConstructor{
template<typename... Args>
T operator()(Args&&...args)const{
return T(std::forward<Args>(args)...);
}
};
struct Foo {
Foo(int a, int b):a(a),b(b){}
int a;
int b;
};
template <typename Fn>
auto Bar(Fn f){
return f(10,20);
}
int main(){
Foo foo = Bar(BindConstructor<Foo>());
}
https://godbolt.org/z/5W383McTc
Hmm, odd. create is a member variable i.e. only available in class instances but the intent of it seems to be creating an instance in the first place.
You cannot take the address of a constructor, but you can create static factory methods of your own and take the address of that.
You can't use regular function pointers on methods, you have to use method pointers, which have bizarre syntax:
void (MyClass::*method_ptr)(int x, int y);
method_ptr = &MyClass::MyMethod;
This gives you a method pointer to MyClass's method - MyMethod. However this isn't a true pointer in that it's not an absolute memory address, it's basically an offset (more complicated than that due to virtual inheritance, but that stuff is implementation specific) into a class. So to use the method pointer, you have to supply it with a class, like this:
MyClass myclass;
myclass.*method_ptr(x, y);
or
MyClass *myclass = new MyClass;
myclass->*method_ptr(x, y);
Of course it should be obvious at this point that you can't use a method pointer to point to an objects constructor. In order to use a method pointer you need to have an instance of the class so it's constructor has already been called! So in your case Michael's Object Factory suggestion is probably the best way of doing it.
Using Qt, you can call a constructor with Qt reflection mechanisms (QMetaObject) if you declare the constructor as Q_INVOKABLE (nothing more to do than that).
class MyClass : public QObject {
Q_OBJECT
public:
Q_INVOKABLE MyClass(int foo);
MyClass *cloningMySelf() {
return metaObject()->newInstance(Q_ARG(int, 42));
}
};
I'm not sure you will want to embed Qt just for that feature ;-) but maybe you would like to have a look on the way it does that.
http://doc.qt.io/qt-5/metaobjects.html#meta-object-system
If you want an actual function pointer representing the constructor, not a functor or closure, you can create a universal factory template:
#include <iostream>
namespace {
template <typename Type, typename... Args>
Type create(Args... args)
{
return Type{std::forward<Args>(args)...};
}
}
template <typename Type, typename... Args>
static constexpr auto constructor = &create<Type, Args...>;
struct Foo {
Foo(double v){ std::cout << "Foo ctor " << v << std::endl; }
};
int main()
{
auto z = constructor<Foo, double>(0.33);
return 0;
}
Foo ctor 0.33
https://godbolt.org/z/qKGGGzjTs
This is similar to Michael Burr's answer, except that you don't have a static factory method per object and it allows any kind of constructor (not just default)
This is similar to bradgonesurfing's answer, except that you create one function pointer per constructor and not one functor per class representing all constructors for that class.
Even though this question is old and already has several very helpful answers, I am adding this additional suggestion because having one function pointer for every constructor of any class is useful when implementing a runtime type reflection system.