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_;
};
Related
Here is a super quick example of what I am thinking.
// Example program
#include <iostream>
#include <string>
class Obj
{
private:
int myInt;
public:
Obj()
{
myInt = 0;
}
~Obj()
{}
void increment()
{
myInt++;
}
int getInt()
{
return myInt;
}
};
class A
{
public:
Obj* myObj;
A()
{
myObj = nullptr;
}
~A()
{
if(myObj)
{
delete myObj;
myObj = nullptr;
}
};
void myFunc(Obj* o)
{
myObj = o;
}
};
int main()
{
A* a = new A();
a->myFunc(new Obj());
a->myObj->increment();
delete a;
}
Just as a hypothetical .... regarding the above code - specifically the line
a->myFunc(new Obj());
It compiles fine, but is there anything functionally wrong with doing this? Other than maybe poor form, or going against best practices?
An important problem with your code is that it's very fragile and bug-prone.
For example, what happens if you have two instances of class A, that point to the same Obj instance?
Suppose that one of the A instances is deleted. Then the object pointed by myObj is destructed. But now the other instance of A has a raw pointer that is pointing to a memory that is not valid anymore.
A better way of storing object pointers, assuming shared ownership semantic, is to use a smart pointer like std::shared_ptr.
For example, in class A replace the raw pointer Obj* myObj with a smart pointer like std::shared_ptr<Obj>, and don't explicitly invoke delete myObj from the A's destructor. Instead, let the std::shared_ptr's destructor automatically handle the deletion of the smart pointer data member. What will happen under the hood is that shared_ptr will use a reference count to figure out when there are no more references to the pointed object, and when this reference count goes to zero, the pointed object will be deleted.
I want to enforce shared_ptr for a few classes. I'm using a static factory function to encapsulating private constructors:
#include <memory>
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
auto a = std::shared_ptr<MyClass>(new MyClass());
return a;
}
private:
MyClass();
~MyClass();
}
}
This template fails with C2440, (function-style cast) in VS2017, but works fine in VS2015 and I have no idea why. A make_shared-version works fine in both but requires public constructors.
Any idea which option I'm missing?
Looks like VS2017 complains about accessing destructor from std::shared_ptr, so you may want to declare std::shared_ptr as friend of MyClass. For std::make_shared you can use a trick from this answer How do I call ::std::make_shared on a class with only protected or private constructors?
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
struct make_shared_enabler : MyClass {};
return std::make_shared<make_shared_enabler>();
}
// compiles fine for gcc without friend though
//friend class std::shared_ptr<MyClass>;
private:
MyClass() {}
~MyClass() {}
};
live example
In addition to other answers: if you don't want to declare std::shared_ptr as a friend of your class and you don't want to make your destructor public, you can create a shared_ptr with the custom deleter. For that you will need some method from your MyClass that can access the private destructor and call delete. For example:
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
auto a = std::shared_ptr<MyClass>(new MyClass(),
[](MyClass* ptr) { destroy(ptr); });
return a;
}
static void destroy(MyClass* ptr) { delete ptr; }
private:
MyClass(){}
~MyClass(){}
};
// later in the source code
auto ptr = MyClass::create();
You can also declare destroy method as non-static and commit a suicide inside (one of a few situations when it actually makes sense).
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 want to use mock object to test my class which uses shared_ptr pointer.
It likes ,
struct MyInterface {
// public functions
};
class MyClass {
public:
MyClass (shared_ptr<MyInterface> handle) : m_handle(handle) {}
~MyClass() {}
// ...
private :
shared_ptr<MyInterface> m_handle;
}
When I test MyClass, I pass a mock object to it.
struct NullDeleter {template<typename T> void operator()(T*) {} };
TMockObject<MyInterface> * mock = new TMockObject<MyInterface>();
shared_ptr<MyInterface> handle((MyInterface*)(*mock), NullDeleter());
MyClass myClass(handle);
delete mock;
the question is I have to use a NullDeleter when i create the shared pointer, otherwise, mock will be delete as a MyInterface which cause error.
Is there any better design for this ?
thanks~
If I could understand what you want to do and I do not take the mistake,
I prefer to have method inside myClass class to check proper value of argument.
It means, you should after pass your argument to class constructor, provide another method to check the value.
Add a virtual destructor to MyInterface, and then when you delete an (abstract) MyInterface, all the sub class destructor is invoked as well.
struct MyInterface {
virtual ~MyInterface() { }
// public functions
};
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...)