I have to register an object in a container upon its creation.
Without smart pointers I'd use something like this:
a_class::a_class()
{
register_somewhere(this);
}
With smart pointers I should use shared_from_this but I can't use that in the constructor.
Is there a clean way to solve this problem? What would you do in a similar situation?
I'm thinking about introducing an init method to call just after creation and put everything in a factory function like this:
boost::shared_ptr<a_class> create_a()
{
boost::shared_ptr<a_class> ptr(new a_class);
ptr->init();
return ptr;
}
Is it fine or there is a standard procedure to follow in such cases?
EDIT: Actually my case is more complex. I have 2 object which shall maintain pointers each other. So the truth is I'm not "registering" but creating another object (let's say b_class) which requires this as a parameter. b_class receives this as a weak pointer and stores it.
I'm adding this because since you are giving me design advices (which are very appreciated) at least you can know what I'm doing:
a_class::a_class()
{
b = new b_class(this);
}
In my program a_class is an entity and b_class is one of the concrete classes representing the state (in the constructor it's just the starting state). a_class needs a pointer to the current state and b_class needs to manipulate the entity.
a_class is responsible for creating and destroying b_class instances and thus maintains a shared_ptr to them but b_class need to manipulate a_class and thus maintains a weak pointer. a_class instance "survives" b_class instances.
Do you suggest to avoid using smart pointers in this case?
a_class is responsible for creating and destroying b_class instances
...
a_class instance "survives" b_class instances.
Given these two facts, there should be no danger that a b_class instance can attempt to access an a_class instance after the a_class instance has been destroyed as the a_class instance is responsible for destroying the b_class instances.
b_class can just hold a pointer to it's associated a_class instance. A raw pointer doesn't express any ownership which is appropriate for this case.
In this example it doesn't matter how the a_class is created, dynamically, part of a aggregated object, etc. Whatever creates a_class manages its lifetime just as a_class manages the lifetime of the b_class which it instantiates.
E.g.
class a_class;
class b_class
{
public:
b_class( a_class* a_ ) : a( a_ ) {}
private:
a_class* a;
};
class a_class
{
public:
a_class() : b( new b_class(this) ) {}
private:
boost::shared_ptr<b_class> b;
};
Note, in this toy example there is no need for a shared_ptr, an object member would work just as well (assuming that you don't copy your entity class).
class a_class
{
public:
a_class() : b( this ) {}
private:
b_class b;
};
If you absolutely need a shared_ptr during construction, it's best to have an 'init' function. In fact, this is the only decent approach I can think of. You should probably have a special function that creates objects of this type, to ensure init() is called, if you choose this path.
However, depending on what you're registering for, it may be a better idea to give whatever object you're registering with a plain pointer to the object in the constructor, rather than a shared_ptr. Then in the destructor, you can just unregister the object from the manager.
Why don't you use http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/enable_shared_from_this.html
struct a_class : enable_shared_from_this<a_class> {
a_class() {
shared_ptr<a_class> ptr(this);
register_somewhere(ptr);
}
};
Update: here is a complete working example:
#include <stdio.h>
#include <boost/smart_ptr/enable_shared_from_this.hpp>
struct a_class;
boost::shared_ptr<a_class> pa;
void register_somewhere(boost::shared_ptr<a_class> p)
{
pa = p;
};
struct a_class : boost::enable_shared_from_this<a_class> {
private:
a_class() {
printf("%s\n", __PRETTY_FUNCTION__);
boost::shared_ptr<a_class> ptr(this);
register_somewhere(ptr);
}
public:
~a_class() {
printf("%s\n", __PRETTY_FUNCTION__);
}
static boost::shared_ptr<a_class> create()
{
return (new a_class)->shared_from_this();
}
};
int main()
{
boost::shared_ptr<a_class> p(a_class::create());
}
Note the factory function a_class::create(). Its job is to make sure that only one reference counter gets created. Because
boost::shared_ptr<a_class> p(new a_class);
Results in creation of two reference counters and double deletion of the object.
There is no need for shared_ptr in your code (as you show it and explain it). A shared_ptr is only appropriate for shared ownership.
Your b_class doesn't own it's a_class, in fact is even outlived by it, so it should merely keep an observing pointer.
If b_class is polymorphic and the manipulations of a_class involve altering its b_class pointer, you should use a unique_ptr<b_class>:
class a_class;
class b_class
{
friend class a_class;
a_class* mya;
b_class(a_class*p)
: mya(p) {}
public:
virtual~b_class() {} // required for unique_ptr<b_class> to work
virtual void fiddle(); // do something to mya
};
class a_class
{
std::unique_ptr<b_class> myb;
public:
a_class()
: myb(new b_class(this)) {}
template<typename B>
void change_myb()
{
myb.reset(new B(this));
}
};
I came up with a helper class for that problem:
template <class Impl>
class ImmediatelySharedFromThis : public std::enable_shared_from_this<Impl> {
typedef std::unique_ptr<void, std::function<void(void*)>> MallocGuard;
typedef std::shared_ptr<Impl> SharedPtr;
// disallow `new MyClass(...)`
static void *operator new(size_t) = delete;
static void *operator new[](size_t) = delete;
static void operator delete[](void*) = delete;
protected:
typedef std::pair<MallocGuard&, SharedPtr&> SharingCookie;
ImmediatelySharedFromThis(SharingCookie cookie) {
MallocGuard &ptr = cookie.first;
SharedPtr &shared = cookie.second;
// This single line contains the actual logic:
shared.reset(reinterpret_cast<Impl*>(ptr.release()));
}
public:
// Create new instance and return a shared pointer to it.
template <class ...Args>
static SharedPtr create(Args &&...args) {
// Make sure that the memory is free'd if ImmediatelySharedFromThis
// is not the first base class, and the initialization
// of another base class throws an exception.
MallocGuard ptr(aligned_alloc(alignof(Impl), sizeof(Impl)), free);
if (!ptr) {
throw std::runtime_error("OOM");
}
SharedPtr result;
::new (ptr.get()) Impl(SharingCookie(ptr, result),
std::forward<Args>(args)...);
return result;
}
static void operator delete(void *ptr) {
free(ptr);
}
};
class MyClass : public ImmediatelySharedFromThis<MyClass> {
friend class ImmediatelySharedFromThis<MyClass>;
MyClass(SharingCookie cookie, int some, int arguments) :
ImmediatelySharedFromThis(cookie)
// You can pass shared_from_this() to other base classes
{
// and you can use shared_from_this() in here, too.
}
public:
....
};
...
std::shared_ptr<MyClass> obj = MyClass::create(47, 11);
A bit ugly, but it works.
For this purpose, I wrote my own drop-in replacement for shared_ptr, weak_ptr and enable_shared_from_this. You can check it out at Sourceforge.
It allows call of shared_from_this() in constructor and destructor without helper functions without space overhead compared to the standard enable_shared_from_this.
Note: creating shared_ptr's in dtors is only allowed as long as they are created only temporarily. That is, they are being destroyed before the dtor returns.
Here's my solution:
class MyClass: enable_shared_from_this<MyClass>
{
public:
//If you use this, you will die.
MyClass(bool areYouBeingAnIdiot = true)
{
if (areYouBeingAnIdiot)
{
throw exception("Don't call this constructor! Use the Create function!");
}
//Can't/Don't use this or shared_from_this() here.
}
static shared_ptr<MyClass> Create()
{
shared_ptr<MyClass> myClass = make_shared<MyClass>(false);
//Use myClass or myClass.get() here, now that it is created.
return myClass;
}
}
//Somewhere.
shared_ptr<MyClass> myClass = MyClass::Create();
(The constructor has to be public to be callable from a static member function, even an internal one...)
Related
What happens when I create a unique pointer using the raw pointer of another unique pointer? In the example below, what would happen when create second class is called? I thought that first_obj_ would give up ownership when second_obj_ is created, but first_obj_ doesn't give up ownership when get is called.
class SecondClass {
SecondClass(Object* obj) : second_obj_(obj) {}
.....
private:
std::unique_ptr<Obj> second_obj_;
}
class FirstClass {
FirstClass() {
std::unique_ptr<Obj> first_obj_ = std::make_unique<Obj>();
}
std::unique_ptr<SecondClass> CreateSecondClass() {
std::make_unique<Obj>(first_obj_.get());
}
.....
private:
std::unique_ptr<Obj> first_obj_;
SecondClass second_class;
}
What happens when I create a unique pointer using the raw pointer of another unique pointer?
BAD THINGS CAN HAPPEN!
You end up with 2 unique_ptr objects that both think they are the exclusive owner of the raw pointer, and so both objects will try to manage and ultimately free the owned memory. To avoid that, you have to pass ownership from one unique_ptr to the other, or else give at least one of the unique_ptrs a custom deleter that does not free the memory (in which case, you shouldn't be using 2 unique_ptr objects to begin with).
In the example below, what would happen when create second class is called?
Both first_obj_ and second_obj_ end up holding pointers to the same Object in memory, and both of them will try to delete it.
I thought that first_obj_ would give up ownership when second_obj_ is created
No, because unique_ptr::get() simply returns a copy of the raw pointer, it does not release ownership of the pointer. If you want that, use unique_ptr::release() instead:
class SecondClass {
public:
SecondClass(Object* obj) : second_obj_(obj) {}
...
private:
std::unique_ptr<Object> second_obj_;
};
class FirstClass {
public:
FirstClass() : first_obj_(std::make_unique<Object>()) {}
std::unique_ptr<SecondClass> CreateSecondClass() {
return std::make_unique<SecondClass>(first_obj_.release());
}
...
private:
std::unique_ptr<Object> first_obj_;
};
Otherwise, you can simply std::move one unique_ptr into the other:
class SecondClass {
public:
SecondClass(std::unique_ptr<Object> obj) : second_obj_(std::move(obj)) {}
...
private:
std::unique_ptr<Object> second_obj_;
};
class FirstClass {
public:
FirstClass() : first_obj_(std::make_unique<Object>()) {}
std::unique_ptr<SecondClass> CreateSecondClass() {
return std::make_unique<SecondClass>(std::move(first_obj_));
}
...
private:
std::unique_ptr<Object> first_obj_;
};
If you truly want FirstClass and SecondClass to share the same pointer, then use std::shared_ptr instead of std::unique_ptr:
class SecondClass {
public:
SecondClass(std::shared_ptr<Object> obj) : second_obj_(obj) {}
...
private:
std::shared_ptr<Object> second_obj_;
};
class FirstClass {
public:
FirstClass() : first_obj_(std::make_shared<Object>()) {}
std::unique_ptr<SecondClass> CreateSecondClass() {
return std::make_unique<SecondClass>(first_obj_);
}
...
private:
std::shared_ptr<Object> first_obj_;
};
You should use release() if you want to give up ownership.
std::unique_ptr cannot know what you will do with the pointer extracted with get() and in particular it cannot know that you decided to give it to another std::unique_ptr.
If two std::shared_ptrs will store the same pointer, you will get double delete of the object, which is Undefined Behaviour.
However, if you want to pass ownership from one std::unique_ptr to another, you should probably use move semantics instead:
class Obj {};
struct SecondClass {
SecondClass(std::unique_ptr<Obj>&& obj) : second_obj_(std::move(obj)) {}
private:
std::unique_ptr<Obj> second_obj_;
};
struct FirstClass {
FirstClass() {
first_obj_ = std::make_unique<Obj>();
}
std::unique_ptr<SecondClass> CreateSecondClass() {
return std::make_unique<SecondClass>(std::move(first_obj_));
//note that first_obj_ points to nullptr now. Only SecondClass owns the Obj.
}
private:
std::unique_ptr<Obj> first_obj_;
};
I have a simple container class that points to an abstract class and I have functions to get/set the pointer in the container class. More concretely, the class looks like this:
class Container
{
Abstract* thing;
public:
void set(Abstract &obj)
{
thing = &obj; //danger of dangling pointer
}
Abstract* get()
{
return thing;
}
};
Abstract is an abstract class. As can be seen already, there's a danger of a dangling pointer. I know that I could make a copy of the object (new) and then point to it. But I can't create an instance of an abstract class. What solutions to this are there?
The following are just more information:
Class definitions
class Abstract
{
public:
virtual void something() = 0;
};
class Base : public Abstract
{
int a;
public:
Base() {}
Base(int a) : a(a){}
virtual void something()
{
cout << "Base" << endl;
}
};
class Derived : public Base
{
int b;
public:
Derived() {}
Derived(int a, int b) : Base(a), b(b){}
virtual void something()
{
cout << "Derived" << endl;
}
};
Simple tests
void setBase(Container &toSet)
{
Base base(15);
toSet.set(base);
}
void setDerived(Container &toSet)
{
Derived derived(10, 30);
toSet.set(derived);
}
int main()
{
Container co;
Base base(15);
Derived derived(10, 30);
Base *basePtr;
Derived *derivedPtr;
//This is fine
co.set(base);
basePtr = static_cast<Base *>(co.get());
basePtr->something();
//This is fine
co.set(derived);
derivedPtr = static_cast<Derived *>(co.get());
derivedPtr->something();
//Reset
basePtr = nullptr;
derivedPtr = nullptr;
//Dangling pointer!
setBase(co);
basePtr = static_cast<Base *>(co.get());
basePtr->something();
//Dangling pointer!
setDerived(co);
derivedPtr = static_cast<Derived *>(co.get());
derivedPtr->something();
return 0;
}
What you need to do is to define your memory ownership concretely.
Container::set accepts an instance of Abstract by reference, which usually does not imply an ownership transfer:
void set(Abstract &obj){...} // Caller retains ownership of obj, but now we have a weak reference to it
Then the onus of deletion is not on you.
Container::get returns a pointer which implies ownership, indicating that someone who calls set should not invalidate the passed object.
Abstract* get(){...}
This could be problematic, as you've stated.
You have a few options
Encode these memory ownership semantics within Container with proper documentation (Code by contract)
Use a smart pointer like std::shared_ptr
In the former case, whether it works or not depends on the user reading and understanding your API, and then behaving nicely with it. In the latter case, the pointer object owns itself, and will delete the allocated memory when the last instance goes out of scope.
void set(std::shared_ptr<Abstract> obj){...}
// now Container participates in the lifetime of obj,
// and it's harder to nullify the underlying object
// (you'd have to be intentionally misbehaving)
If you are worried about the object being deallocated elsewhere resulting in a dangling pointer, you could use boost smart pointers.
Boost smart pointers would provide you the service of book keeping and help to avoid such a case.
Some information can be found here :
smart pointers (boost) explained
This is what std::unique_ptr is for:
class Container
{
std::unique_ptr<Abstract> thing;
public:
void set(std::unique_ptr<Abstract> obj)
{
thing = obj;
}
Abstract* get()
{
return thing.get();
}
};
Now the Abstract object is "owned" by Container and will be cleaned up automatically when the Conatiner is destroyed.
If you want a pointer that might live longer, or might be shared between mulitple containers, use std::shared_ptr instead.
I have two classes, for instance, A and B. I would like to pass A as reference to B.
class I
{
public:
virtual void callback() = 0;
};
class B
{
public:
B(I* callback) : _callback(callback) {}
private:
I* _callback;
};
class A : public I
{
public:
A() : _b(new B(this)) {}
private:
B* _b;
};
And I would like to:
get rid of naked pointers (for instance, with a help of std::shared_ptr and std::weak_ptr).
avoid cyclic referencing.
But there are some problems:
How do I create a weak pointer INSIDE a class A? First, I should be sure that an instance of A is managed by some shared_ptr. Even if I'm really sure, how can I find this shared_ptr instance?
Generally, how can I ensure that I'm using instances of some class ONLY via shared pointers? I can try to create factory method and make constructor private, but it leads to error: make_shared demands a public contstructor.
Thanks in advance!
EDIT:
More detail explanation of problem: I have a class A. This class wants to pass some part of work to a class B. So I have a shared pointer to B inside A. And I would like B to do this asynchronously, and B should call A's callback when there is some progress or when the work is done. So B should have a reference to A.
class I
{
public:
virtual void isDone() = 0;
};
class B
{
public:
B(I* callback) : _callback(callback) //how do I take and store callback inside B???
{
//async invocation of run()
}
private:
weak_ptr<I> _callback;
void run()
{
if(_callback.get())
{
_callback->isDone();
}
}
};
class A : public I
{
public:
A() : _b(new B(this)) {} //how do I pass this to B???
private:
shared_ptr<B> _b;
virtual void isDone()
{
cout << "job is complete" << '\n';
}
};
So the question is: how do I pass A to B? I can try to do it via naked pointer or reference, but it's safety because B has no guarantees that this referenced object is still alive (common problem of all naked pointers). So I would like to pass a weak pointer, and my question was all about it.
The first problem can be solved with std::enable_shared_from_this, which allows you to safely create a shared pointer instance from within class A.
The second problem may be solved by using a static factory method belonging to class A and not using std::make_shared like this:
static std::shared_ptr<A> create() {
return std::shared_ptr<A>(new A());
}
Then, you can make A's constructor private.
In C++, I want to define an object as a member of a class like this:
Object myObject;
However doing this will try to call it's parameterless constructor, which doesn't exist. However I need the constructor to be called after the containing class has done some initialising. Something like this.
class Program
{
public:
Object myObject; //Should not try to call the constructor or do any initializing
Program()
{
...
//Now call the constructor
myObject = Object(...);
}
}
Store a pointer to an Object rather than an actual Object
thus:
class Program
{
public:
Object* myObject; // Will not try to call the constructor or do any initializing
Program()
{
//Do initialization
myObject = new Object(...); // Initialised now
}
}
Don't forget to delete it in the destructor. Modern C++ helps you there, in that you could use an auto_ptr shared_ptr rather than a raw memory pointer.
Others have posted solutions using raw pointers, but a smart pointer would be a better idea:
class MyClass {
std::unique_ptr<Object> pObj;
// use boost::scoped_ptr for older compilers; std::unique_ptr is a C++0x feature
public:
MyClass() {
// ...
pObj.reset(new Object(...));
pObj->foo();
}
// Don't need a destructor
};
This avoids the need to add a destructor, and implicitly forbids copying (unless you write your own operator= and MyClass(const MyClass &).
If you want to avoid a separate heap allocation, this can be done with boost's aligned_storage and placement new. Untested:
template<typename T>
class DelayedAlloc : boost::noncopyable {
boost::aligned_storage<sizeof(T)> storage;
bool valid;
public:
T &get() { assert(valid); return *(T *)storage.address(); }
const T &get() const { assert(valid); return *(const T *)storage.address(); }
DelayedAlloc() { valid = false; }
// Note: Variadic templates require C++0x support
template<typename Args...>
void construct(Args&&... args)
{
assert(!valid);
new(storage.address()) T(std::forward<Args>(args)...);
valid = true;
}
void destruct() {
assert(valid);
valid = false;
get().~T();
}
~DelayedAlloc() { if (valid) destruct(); }
};
class MyClass {
DelayedAlloc<Object> obj;
public:
MyClass() {
// ...
obj.construct(...);
obj.get().foo();
}
}
Or, if Object is copyable (or movable), you can use boost::optional:
class MyClass {
boost::optional<Object> obj;
public:
MyClass() {
// ...
obj = Object(...);
obj->foo();
}
};
You can fully control the object construction and destruction by this trick:
template<typename T>
struct DefferedObject
{
DefferedObject(){}
~DefferedObject(){ value.~T(); }
template<typename...TArgs>
void Construct(TArgs&&...args)
{
new (&value) T(std::forward<TArgs>(args)...);
}
public:
union
{
T value;
};
};
Apply on your sample:
class Program
{
public:
DefferedObject<Object> myObject; //Should not try to call the constructor or do any initializing
Program()
{
...
//Now call the constructor
myObject.Construct(....);
}
}
Big advantage of this solution, is that it does not require any additional allocations, and object memory allocated as normal, but you have control when call to constructor.
Another sample link
If you have access to boost, there is a handy object that is provided called boost::optional<> - this avoids the need for dynamic allocation, e.g.
class foo
{
foo() // default std::string ctor is not called..
{
bar = boost::in_place<std::string>("foo"); // using in place construction (avoid temporary)
}
private:
boost::optional<std::string> bar;
};
You may also be able to rewrite your code to use the constructor initializer list, if you can move off the other initialization into constructors:
class MyClass
{
MyObject myObject; // MyObject doesn't have a default constructor
public:
MyClass()
: /* Make sure that any other initialization needed goes before myObject in other initializers*/
, myObject(/*non-default parameters go here*/)
{
...
}
};
You need to be aware that following such a pattern will lead you to a path where you do a lot of work in constructors, which in turn leads to needing to grasp exception handling and safety (as the canonical way to return an error from a constructor is to throw an exception).
You can use a pointer (or a smart pointer) to do that. If you do not use a smart pointer, do make sure that your code free memory when the object is deleted. If you use a smart pointer, do not worry about it.
class Program
{
public:
Object * myObject;
Program():
myObject(new Object())
{
}
~Program()
{
delete myObject;
}
// WARNING: Create copy constructor and = operator to obey rule of three.
}
A trick that involves anonymous union and placement new
this is similar to jenkas' answer but more direct
class Program
{
public:
union{
Object myObject;
}; //being a union member in this case prevents the compiler from attempting to call the (undefined) default constructor
Program()
{
...
//Now call the constructor
new (&myObject) Object(...);
}
~Program()
{
myobject.~Object(); //also make sure you explicitly call the object's destructor
}
}
however the catch is that now you must explicitly define all the special member functions as the compiler will delete them by default.
I want to instantiate a base class pointer to point to a newly constructed derived class object. The actual class for the object will change depending on the application type, so I want to use a Factory method to switch on certain variables in order to construct the right object.
However I don't want to have to do the switch each time. In fact, once the application starts, the type of object I want to create in this situation will always be the same - so actually I only need to do this switch only once.
Can I pass in a derived class Constructor to the function creating the object?
For example:
typedef DerivedObject (*DerivedClassConstructor)( void );
class ContainingClass:
{
public:
ContainingClass ( DerivedClassConstructor * f )
{
baseptr = f();
}
BaseClass * baseptr
};
Is there a better design?
Would it not be easier to templatise the code.
That way it looks like normal code.
class BaseClass
{};
class Derived: public BaseClass
{};
template<typename T>
class ContainingClass
{
public:
ContainingClass()
{
baseptr = new T();
}
BaseClass * baseptr;
};
int main()
{
ContainingClass<Derived> cont;
}
I think that's pretty sane. Just pass a function object and save it since it seems you need to recall it later (otherwise why not pass the pointer directly and create the object before?)
class ContainingClass:
{
public:
typedef boost::function<BaseClass*()> factory_fn;
public:
ContainingClass (factory_fn f )
:m_f(f)
{
baseptr = m_f();
}
BaseClass * baseptr
factory_fn m_f;
};
template<typename T>
struct DerivedFactory {
BaseClass *operator()() {
return new T;
}
};
ContainingClass c((DerivedFactory<DerivedClass>()));
You can't do it with a constructor, since a constructor is not actually returning a class instance.
You talk about a factory method, and you got half way towards actually using one. However, it is not a good idea to create a dependency from base class to derived class - why can't your factory method simply return (a pointer to) BaseClass objects?
typedef BaseClass* (*BaseClassFactory)( void );