Reputation: 2211
I have a class that need to call shared_from_this()
for its initialization. As it is not possible to directly call this function inside the ctor, then i have to do it in 2 steps :
It works however ideally, i would like the client code only to make one single call for it - and make the init
function private as it is a part of the construction.
Is this possible ?
There is also a side note in the comments following exception: bad_weak_ptr while shared_from_this because it does not work in my case ( but maybe it's another question )
#include <iostream>
#include <memory>
class Foo;
void globalInit(std::shared_ptr<Foo> foo, int val)
{
(void)foo;
std::cout << __PRETTY_FUNCTION__ << val <<std::endl;
}
class Foo : public std::enable_shared_from_this<Foo>
{
public:
static std::shared_ptr<Foo> create(int val) {
return std::shared_ptr<Foo>(new Foo(val));
/*
* side note : if i use return std::make_shared<Foo>(val);
* then i have a compiler error with g++ (Debian 6.3.0-18)
* "Foo::Foo(int) is private within this context"
*/
}
// it should not be public ..
void init() {
// during init, i need to call shared_from_this()
// and access private members
globalInit(shared_from_this(), m_val);
}
private:
// i cannot call shared_from_this() in the ctor
explicit Foo(int val) : m_val(val) {}
private:
int m_val;
};
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
// create the object
std::shared_ptr<Foo> foo = Foo::create(0);
// initialize it
foo->init();
// now it's ready to use
// ...
return 0;
}
Thank you.
Upvotes: 1
Views: 120
Reputation: 136286
If you:
std::week_ptr
,boost
libraries,than boost::intrusive_ptr
is all around a better choice than std::shared_ptr
because:
sizeof(boost::intrusive_ptr<T>) == sizeof(std::shared_ptr<T>) / 2
.std::shared_ptr
always uses two atomic counters (one for the object, another for the control block itself).std::make_shared
).T
and make boost::intrusive_ptr<T>
when you need them. This may be dangerous because you must be sure that the object is heap allocated. Nevertheless, you can, if you need to, no factory is needed.Example:
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
#include <iostream>
struct Foo;
void globalInit(Foo*);
struct Foo : boost::intrusive_ref_counter<Foo, boost::thread_unsafe_counter> {
Foo() {
globalInit(this);
}
};
boost::intrusive_ptr<Foo> global_copy;
void globalInit(Foo* foo) {
std::cout << __PRETTY_FUNCTION__ << '\n';
global_copy.reset(foo);
}
int main() {
boost::intrusive_ptr<Foo> a(new Foo);
std::cout << (a == global_copy) << '\n';
}
Upvotes: 1
Reputation: 217398
You might call init
from your factory:
class Foo : public std::enable_shared_from_this<Foo>
{
private:
class private_key{
private:
friend class Foo;
private_key() {}
};
public:
static std::shared_ptr<Foo> create(int val) {
auto p = std::make_shared<Foo>(private_key{}, val);
p->init(); // Or directly globalInit(p, p->m_val);
return p;
}
private:
void init() {
// during init, I need to call shared_from_this()
// and access private members
globalInit(shared_from_this(), m_val);
}
public: // But only callable internally thanks to private_key
Foo(private_key, int val) : m_val(val) {}
private:
int m_val;
};
Upvotes: 3