Are all members of a Smart Pointer allocated on the Heap? - c++

Given the following code:
#include <unordered_map>
#include <memory>
#include <string>
class Element {
public:
Element(const std::string& value) {
m_value = value;
}
private:
std::string m_value;
};
class Container {
public:
Container(const std::string& value) {
m_elements.emplace(std::make_pair("New Key",Element(value)));
}
private:
std::unordered_map<std::string, Element> m_elements;
};
int main() {
std::string str {"New Value"};
auto container = std::make_shared<Container>(str);
return 0;
}
Will all members of the Container shared_ptr instance be stored on Heap, including all instances of the Element class inside the m_elements unordered_map? My question comes down to: Are all members of a shared_ptr stored on the Heap?

Are all members of a Smart Pointer allocated on the Heap?
If an object has dynamic storage duration, then by definition, that object is not a member object. All data members are stored within the memory of the enclosing object.
A smart pointer is a stateful object, and in practice, it needs at least one subject to represent that state. It could be a direct data member, or a data member of a base class.
std::make_shared<Container> crates an instance of Container with dynamic storage duration, and returns a shared pointer that owns the instance.

Related

Using map for storage while accessing with baseclass?

I'm using an std::map for storage (storing data on the stack).
This map is happened to store items which are derived instances of a base class:
class Base {
public:
int id;
Base(int id): id(id) {}
void baseFn() {}
};
class Derived : public Base {
public:
Derived(int id): Base(id) {}
};
std::map<int, Derived> storage;
My question is more theoretical than practical (as I know a few solutions):
I have to pass this storage to a function (register_cb) requires void* as its parameter. This function is not owned by me, and I can't change it.
Later, a callback function (cb) will pass me this pointer, and I wish to use it to get back my storage:
//void register_cb(void* data);
register_cb(&storage);
void cb(void* data) {
//get back my storage
std::map<int, Derived>* storage = static_cast<std::map<int, Derived>*>(data);
}
Now this is a bit ugly, but anyway it works.
What I wish to accomplish is to access the storage from callbacks where I don't know the Derived class, only the Base:
I wish to iterate through the map, and call baseFn on every single item. Can I somehow safely cast std::map<int, Derived> to std::map<int, Base pointer or reference or whatever>?

Smart pointers and derived classes

I am going to store a large quantity of objects in a std::list.
Since I need those objects to store different types of data, I am storing pointers to a base class which only holds an attribute of an enum type which tells the objects to which of the derived classes it should be casted to. Each derived class has then its own type of data:
struct Base {
enum class Type {
D1,
D2,
...
} type;
Base(Type new_type):
type(new_type) {}
};
struct D1: public Base {
std::string data;
D1(std::string new_data):
Base(Base::Type::D1), data(new_data) {}
};
struct D2: public Base {
double data;
D2(double new_data):
Base(Base::Type::D2), data(new_data) {}
};
To hold pointers to these objects, I am using smart pointers:
std::list<std::unique_ptr<Base>> list;
list.push_back(std::unique_ptr<Base>(new D1("Somestring")));
list.push_back(std::unique_ptr<Base>(new D2(3.14)));
However, while each Base object knows what type it should be casted to to get deleted properly, the smart pointer only knows that it must call Base's destructor. Which would leave undeleted the memory each subclass allocated.
How would I pass a custom deleter to the smart pointers so that they know how to properly cast and free each object's memory? What should I implement that custom deleter?
Just mark the destructor of Base as virtual. Then the default deleter will invoke delete pointer_to_raw_object;, which will call the right destructor based on the dynamic type of object.
Example:
#include <iostream>
#include <memory>
#include <list>
struct Base
{
virtual ~Base(){std::cout << __PRETTY_FUNCTION__ << std::endl;}
};
struct Derived : Base
{
~Derived() override {std::cout << __PRETTY_FUNCTION__ << std::endl;}
};
int main()
{
std::list<std::unique_ptr<Base>> l;
l.emplace_back(new Base);
l.emplace_back(new Derived);
}
Live on Coliru
PS: consider using std::list::emplace_back for cleaner (and more efficient) code.

How to initialize a non-const attribute of a const object with a const value?

I need to instantiate a const object of my class, and initialize its members pointers from const pointers. Is that possible? How to do it?
I have something of the kind:
class A:
public Base
{
public:
A():
v(nullptr)
{}
virtual void f() override
{}
private:
my_type *v;
friend void f(const my_type& orig)
{
// How to create a "const A" with "v == &orig" ?
}
};
Whether an object itself is constant and whether any of its class members are constant, are two completely separate topics.
Whether or not a members of a class can be initialized in a particular way does not depend on whether a particular instance of the class is constant, or not.
A pointer to a constant object cannot be used to initialize a pointer to a non-constant object. Your class member:
my_type *v;
is a pointer to a non-constant object (presuming that my_type itself is not a constant type).
As such, this pointer cannot be initialized to point to a constant object.
Whether or not some instance of the class, containing this member, is constant, or not, is not a factor.

Initialization of a struct instance data member in constructor?

I have a c++ class which as a private data member has a struct defined:
Class example {
...
private:
struct Impl;
Impl& structure_;
};
Assuming that the struct Impl is defined as follows:
struct example::Impl{
int m1;
int m2;
int m3;
};
how would I be able to initialize the struct instance ( structure_ ) in the class's constructor?
Right now I have:
example::example() :
structure_ .m1(00),
structure_ .m2(00),
structure_ .m3(00) {
...
}
.. for the initialization list, but I'm getting this error:
'example::structure_' : must be initialized in constructor base/member initializer list
how would I fix this?
Thanks
Impl is a reference, so you need to initialize it with an actual Impl object before it can be used.
If you're going for the pImpl idiom, use a pointer, and allocate + deallocate it in the class, then assign to it inside the ctor.
Class example {
...
private:
struct Impl;
Impl* pimpl_
};
example::example() :
pimpl_(new Impl())
{
pimpl_->m1 = 00;
pimpl_->m2 = 00;
pimpl_->m3 = 00;
...
}
example::~example(){
delete pimpl_;
}
If you really want a reference, dereference the returned pointer from new and take its address again when deleting it:
example::example() : impl_(*new Impl(), ...
example::~example(){ delete &impl_; }
Since your structure_ is a reference, it needs to be referenced by something that is created outside of your "example" class. You could either change the reference into a pointer and allocate the structure somehow, or define the structure in the class-definition, allowing you to instance it directly instead of using a reference.
You store your struct by reference in your class. A reference must point to a physical object, you can do two things. Store the object by value or by pointer.

shared_from_this called from constructor

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...)