Defer pattern for constructors in C++
$begingroup$
In some specific scenarios, I want to run code after the constructor for a class has run (namely: access std::enable_shared_from_this::shared_from_this()).
To solve this without introducing an error prone init method for all classes with this behaviour I have built a generic pattern that allows constructors to "defer" lambdas to run after the constructor has run (example in end of snippet):
// If derived from this subclasses may call enable_defer::defer in their
// constructor to run code directly _after_ their constructor has completed
// This is useful when for example the constructor wants to access the weak_ptr
// from std::enable_shared_from_this in the constructor.
// Note naming convention matching std::enable_shared_from_this & underscores to avoid collisions in subclasses
class enable_defer
{
// Allowed factories
template <typename T>
friend std::shared_ptr<T> make_shared_deferrable();
template <typename T, typename... Args>
friend std::shared_ptr<T> make_shared_deferrable(Args&&... args);
// Allowed implementations
template <typename T>
friend class __impl__;
private:
std::vector<std::function<void()>> defered;
bool constructed = false;
// Only friend classes may have access to this type
// this is because we only want friend classes to be able to implement the interface
class __Tag__ {};
virtual void __constructed__(__Tag__ = __Tag__()) = 0;
// Implementation of enable_defer kept private
// to make sure only friend factories above may
// construct implementations
template <typename T>
class __impl__ : public T
{
static_assert(std::is_base_of<enable_defer, T>::value, "Must be enable_defer");
// Forward base class constructors
using T::T;
virtual void __constructed__(__Tag__) override
{
constructed = true;
for (auto fn : defered)
fn();
}
};
protected:
void defer(std::function<void()> fn)
{
// Make sure defer is only called in constructor
assert(!constructed);
defered.push_back(fn);
}
};
// Create std::shared_ptr from enable_defer
template <typename T>
std::shared_ptr<T> make_shared_deferrable()
{
auto shared(std::shared_ptr<T>(new enable_defer::__impl__<T>()));
shared->__constructed__();
return shared;
}
// Create std::shared_ptr from enable_defer
template <typename T, typename... Args>
std::shared_ptr<T> make_shared_deferrable(Args&&... args)
{
auto shared(std::shared_ptr<T>(new enable_defer::__impl__<T>(std::forward<Args>(args)...)));
shared->__constructed__();
return shared;
}
class Example : public enable_defer, public std::enable_shared_from_this<Example>
{
public:
Example()
{
defer([this]() {
shared_from_this(); // Works!
});
}
// Factory
static std::shared_ptr<Example> create()
{
return make_shared_deferrable<Example>();
}
};
Questions:
- Are there better ways to accomplish the enforcements of the implementation class and factories?
- General improvements
- Bugs?
- Naming?
- General thoughts on this pattern.
c++ design-patterns template-meta-programming
$endgroup$
add a comment |
$begingroup$
In some specific scenarios, I want to run code after the constructor for a class has run (namely: access std::enable_shared_from_this::shared_from_this()).
To solve this without introducing an error prone init method for all classes with this behaviour I have built a generic pattern that allows constructors to "defer" lambdas to run after the constructor has run (example in end of snippet):
// If derived from this subclasses may call enable_defer::defer in their
// constructor to run code directly _after_ their constructor has completed
// This is useful when for example the constructor wants to access the weak_ptr
// from std::enable_shared_from_this in the constructor.
// Note naming convention matching std::enable_shared_from_this & underscores to avoid collisions in subclasses
class enable_defer
{
// Allowed factories
template <typename T>
friend std::shared_ptr<T> make_shared_deferrable();
template <typename T, typename... Args>
friend std::shared_ptr<T> make_shared_deferrable(Args&&... args);
// Allowed implementations
template <typename T>
friend class __impl__;
private:
std::vector<std::function<void()>> defered;
bool constructed = false;
// Only friend classes may have access to this type
// this is because we only want friend classes to be able to implement the interface
class __Tag__ {};
virtual void __constructed__(__Tag__ = __Tag__()) = 0;
// Implementation of enable_defer kept private
// to make sure only friend factories above may
// construct implementations
template <typename T>
class __impl__ : public T
{
static_assert(std::is_base_of<enable_defer, T>::value, "Must be enable_defer");
// Forward base class constructors
using T::T;
virtual void __constructed__(__Tag__) override
{
constructed = true;
for (auto fn : defered)
fn();
}
};
protected:
void defer(std::function<void()> fn)
{
// Make sure defer is only called in constructor
assert(!constructed);
defered.push_back(fn);
}
};
// Create std::shared_ptr from enable_defer
template <typename T>
std::shared_ptr<T> make_shared_deferrable()
{
auto shared(std::shared_ptr<T>(new enable_defer::__impl__<T>()));
shared->__constructed__();
return shared;
}
// Create std::shared_ptr from enable_defer
template <typename T, typename... Args>
std::shared_ptr<T> make_shared_deferrable(Args&&... args)
{
auto shared(std::shared_ptr<T>(new enable_defer::__impl__<T>(std::forward<Args>(args)...)));
shared->__constructed__();
return shared;
}
class Example : public enable_defer, public std::enable_shared_from_this<Example>
{
public:
Example()
{
defer([this]() {
shared_from_this(); // Works!
});
}
// Factory
static std::shared_ptr<Example> create()
{
return make_shared_deferrable<Example>();
}
};
Questions:
- Are there better ways to accomplish the enforcements of the implementation class and factories?
- General improvements
- Bugs?
- Naming?
- General thoughts on this pattern.
c++ design-patterns template-meta-programming
$endgroup$
add a comment |
$begingroup$
In some specific scenarios, I want to run code after the constructor for a class has run (namely: access std::enable_shared_from_this::shared_from_this()).
To solve this without introducing an error prone init method for all classes with this behaviour I have built a generic pattern that allows constructors to "defer" lambdas to run after the constructor has run (example in end of snippet):
// If derived from this subclasses may call enable_defer::defer in their
// constructor to run code directly _after_ their constructor has completed
// This is useful when for example the constructor wants to access the weak_ptr
// from std::enable_shared_from_this in the constructor.
// Note naming convention matching std::enable_shared_from_this & underscores to avoid collisions in subclasses
class enable_defer
{
// Allowed factories
template <typename T>
friend std::shared_ptr<T> make_shared_deferrable();
template <typename T, typename... Args>
friend std::shared_ptr<T> make_shared_deferrable(Args&&... args);
// Allowed implementations
template <typename T>
friend class __impl__;
private:
std::vector<std::function<void()>> defered;
bool constructed = false;
// Only friend classes may have access to this type
// this is because we only want friend classes to be able to implement the interface
class __Tag__ {};
virtual void __constructed__(__Tag__ = __Tag__()) = 0;
// Implementation of enable_defer kept private
// to make sure only friend factories above may
// construct implementations
template <typename T>
class __impl__ : public T
{
static_assert(std::is_base_of<enable_defer, T>::value, "Must be enable_defer");
// Forward base class constructors
using T::T;
virtual void __constructed__(__Tag__) override
{
constructed = true;
for (auto fn : defered)
fn();
}
};
protected:
void defer(std::function<void()> fn)
{
// Make sure defer is only called in constructor
assert(!constructed);
defered.push_back(fn);
}
};
// Create std::shared_ptr from enable_defer
template <typename T>
std::shared_ptr<T> make_shared_deferrable()
{
auto shared(std::shared_ptr<T>(new enable_defer::__impl__<T>()));
shared->__constructed__();
return shared;
}
// Create std::shared_ptr from enable_defer
template <typename T, typename... Args>
std::shared_ptr<T> make_shared_deferrable(Args&&... args)
{
auto shared(std::shared_ptr<T>(new enable_defer::__impl__<T>(std::forward<Args>(args)...)));
shared->__constructed__();
return shared;
}
class Example : public enable_defer, public std::enable_shared_from_this<Example>
{
public:
Example()
{
defer([this]() {
shared_from_this(); // Works!
});
}
// Factory
static std::shared_ptr<Example> create()
{
return make_shared_deferrable<Example>();
}
};
Questions:
- Are there better ways to accomplish the enforcements of the implementation class and factories?
- General improvements
- Bugs?
- Naming?
- General thoughts on this pattern.
c++ design-patterns template-meta-programming
$endgroup$
In some specific scenarios, I want to run code after the constructor for a class has run (namely: access std::enable_shared_from_this::shared_from_this()).
To solve this without introducing an error prone init method for all classes with this behaviour I have built a generic pattern that allows constructors to "defer" lambdas to run after the constructor has run (example in end of snippet):
// If derived from this subclasses may call enable_defer::defer in their
// constructor to run code directly _after_ their constructor has completed
// This is useful when for example the constructor wants to access the weak_ptr
// from std::enable_shared_from_this in the constructor.
// Note naming convention matching std::enable_shared_from_this & underscores to avoid collisions in subclasses
class enable_defer
{
// Allowed factories
template <typename T>
friend std::shared_ptr<T> make_shared_deferrable();
template <typename T, typename... Args>
friend std::shared_ptr<T> make_shared_deferrable(Args&&... args);
// Allowed implementations
template <typename T>
friend class __impl__;
private:
std::vector<std::function<void()>> defered;
bool constructed = false;
// Only friend classes may have access to this type
// this is because we only want friend classes to be able to implement the interface
class __Tag__ {};
virtual void __constructed__(__Tag__ = __Tag__()) = 0;
// Implementation of enable_defer kept private
// to make sure only friend factories above may
// construct implementations
template <typename T>
class __impl__ : public T
{
static_assert(std::is_base_of<enable_defer, T>::value, "Must be enable_defer");
// Forward base class constructors
using T::T;
virtual void __constructed__(__Tag__) override
{
constructed = true;
for (auto fn : defered)
fn();
}
};
protected:
void defer(std::function<void()> fn)
{
// Make sure defer is only called in constructor
assert(!constructed);
defered.push_back(fn);
}
};
// Create std::shared_ptr from enable_defer
template <typename T>
std::shared_ptr<T> make_shared_deferrable()
{
auto shared(std::shared_ptr<T>(new enable_defer::__impl__<T>()));
shared->__constructed__();
return shared;
}
// Create std::shared_ptr from enable_defer
template <typename T, typename... Args>
std::shared_ptr<T> make_shared_deferrable(Args&&... args)
{
auto shared(std::shared_ptr<T>(new enable_defer::__impl__<T>(std::forward<Args>(args)...)));
shared->__constructed__();
return shared;
}
class Example : public enable_defer, public std::enable_shared_from_this<Example>
{
public:
Example()
{
defer([this]() {
shared_from_this(); // Works!
});
}
// Factory
static std::shared_ptr<Example> create()
{
return make_shared_deferrable<Example>();
}
};
Questions:
- Are there better ways to accomplish the enforcements of the implementation class and factories?
- General improvements
- Bugs?
- Naming?
- General thoughts on this pattern.
c++ design-patterns template-meta-programming
c++ design-patterns template-meta-programming
edited Dec 21 '18 at 10:13
monoceres
asked Dec 21 '18 at 10:05
monoceresmonoceres
1212
1212
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
Identifiers with leading underscore(s) followed by a capital letter are reserved for the implementation and should not be used in your own code. It's easiest to just avoid leading underscores.
When using
enable_shared_from_this
it's important to use a static factory function and make the other constructors private. This prevents calling theExample
constructor directly (where callingshared_from_this
will be undefined behaviour, since we don't have ashared_ptr
).
Do we really need enable_shared_from_this
? The whole thing could be more easily written as:
class Example
{
private:
Example() { }
public:
static std::shared_ptr<Example> Create()
{
auto example = std::make_shared<Example>();
example->do_the_thing();
return example;
}
};
It really depends on what do_the_thing()
is...
If we have to register the class somewhere after creation (or consistently perform some action), perhaps that logic doesn't belong in the Example
class at all.
struct Example {};
struct Registry
{
template<class T, class... Args>
std::shared_ptr<T> CreateAndRegister(Args&&... args)
{
auto object = std::make_shared<T>(std::forward<Args>(args)...);
Register(object);
return object;
}
};
auto registry = Registry();
auto e = registry.CreateAndRegister<Example>();
While an object has control over it's own copy / move semantics, it generally shouldn't care who / what owns it.
So the question is: why does Example
need to "break the 4th wall" and know that it exists inside a shared_ptr
?
Large inheritance hierarchies are out of fashion nowadays (with good reason), but with a general solution, you may need to cope with:
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : ExampleA {}; // what if B wants to defer something?
and
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : enable_defer, enable_shared_from_this<ExampleB> {};
struct ExampleC : ExampleA, ExampleB {}; // uh oh... ?
shared_from_this
is quite complicated to use as it is with a class hierarchy.
$endgroup$
$begingroup$
I generally agree that std::enable_shared_from_this is bad practice. In my use case, Example needs to register itself as a listener on a child object (that is created in the constructor as well) that takes a shared_ptr/weak_ptr. It's one of the few instances where I think it's appropriate, but I rather implement this general pattern than hard code it into the classes that needs it.
$endgroup$
– monoceres
Dec 21 '18 at 11:45
$begingroup$
If it's a child object, and you can change the interface, can it not just take a raw pointer? The lifetimes should be well defined, and the child object probably shouldn't own it's parent. Otherwise, I'd still argue for a plain factory function. It's one function call, vs. one function call and multiple inheritance to add an intrusive deferral mechanism.
$endgroup$
– user673679
Dec 21 '18 at 12:01
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210108%2fdefer-pattern-for-constructors-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Identifiers with leading underscore(s) followed by a capital letter are reserved for the implementation and should not be used in your own code. It's easiest to just avoid leading underscores.
When using
enable_shared_from_this
it's important to use a static factory function and make the other constructors private. This prevents calling theExample
constructor directly (where callingshared_from_this
will be undefined behaviour, since we don't have ashared_ptr
).
Do we really need enable_shared_from_this
? The whole thing could be more easily written as:
class Example
{
private:
Example() { }
public:
static std::shared_ptr<Example> Create()
{
auto example = std::make_shared<Example>();
example->do_the_thing();
return example;
}
};
It really depends on what do_the_thing()
is...
If we have to register the class somewhere after creation (or consistently perform some action), perhaps that logic doesn't belong in the Example
class at all.
struct Example {};
struct Registry
{
template<class T, class... Args>
std::shared_ptr<T> CreateAndRegister(Args&&... args)
{
auto object = std::make_shared<T>(std::forward<Args>(args)...);
Register(object);
return object;
}
};
auto registry = Registry();
auto e = registry.CreateAndRegister<Example>();
While an object has control over it's own copy / move semantics, it generally shouldn't care who / what owns it.
So the question is: why does Example
need to "break the 4th wall" and know that it exists inside a shared_ptr
?
Large inheritance hierarchies are out of fashion nowadays (with good reason), but with a general solution, you may need to cope with:
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : ExampleA {}; // what if B wants to defer something?
and
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : enable_defer, enable_shared_from_this<ExampleB> {};
struct ExampleC : ExampleA, ExampleB {}; // uh oh... ?
shared_from_this
is quite complicated to use as it is with a class hierarchy.
$endgroup$
$begingroup$
I generally agree that std::enable_shared_from_this is bad practice. In my use case, Example needs to register itself as a listener on a child object (that is created in the constructor as well) that takes a shared_ptr/weak_ptr. It's one of the few instances where I think it's appropriate, but I rather implement this general pattern than hard code it into the classes that needs it.
$endgroup$
– monoceres
Dec 21 '18 at 11:45
$begingroup$
If it's a child object, and you can change the interface, can it not just take a raw pointer? The lifetimes should be well defined, and the child object probably shouldn't own it's parent. Otherwise, I'd still argue for a plain factory function. It's one function call, vs. one function call and multiple inheritance to add an intrusive deferral mechanism.
$endgroup$
– user673679
Dec 21 '18 at 12:01
add a comment |
$begingroup$
Identifiers with leading underscore(s) followed by a capital letter are reserved for the implementation and should not be used in your own code. It's easiest to just avoid leading underscores.
When using
enable_shared_from_this
it's important to use a static factory function and make the other constructors private. This prevents calling theExample
constructor directly (where callingshared_from_this
will be undefined behaviour, since we don't have ashared_ptr
).
Do we really need enable_shared_from_this
? The whole thing could be more easily written as:
class Example
{
private:
Example() { }
public:
static std::shared_ptr<Example> Create()
{
auto example = std::make_shared<Example>();
example->do_the_thing();
return example;
}
};
It really depends on what do_the_thing()
is...
If we have to register the class somewhere after creation (or consistently perform some action), perhaps that logic doesn't belong in the Example
class at all.
struct Example {};
struct Registry
{
template<class T, class... Args>
std::shared_ptr<T> CreateAndRegister(Args&&... args)
{
auto object = std::make_shared<T>(std::forward<Args>(args)...);
Register(object);
return object;
}
};
auto registry = Registry();
auto e = registry.CreateAndRegister<Example>();
While an object has control over it's own copy / move semantics, it generally shouldn't care who / what owns it.
So the question is: why does Example
need to "break the 4th wall" and know that it exists inside a shared_ptr
?
Large inheritance hierarchies are out of fashion nowadays (with good reason), but with a general solution, you may need to cope with:
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : ExampleA {}; // what if B wants to defer something?
and
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : enable_defer, enable_shared_from_this<ExampleB> {};
struct ExampleC : ExampleA, ExampleB {}; // uh oh... ?
shared_from_this
is quite complicated to use as it is with a class hierarchy.
$endgroup$
$begingroup$
I generally agree that std::enable_shared_from_this is bad practice. In my use case, Example needs to register itself as a listener on a child object (that is created in the constructor as well) that takes a shared_ptr/weak_ptr. It's one of the few instances where I think it's appropriate, but I rather implement this general pattern than hard code it into the classes that needs it.
$endgroup$
– monoceres
Dec 21 '18 at 11:45
$begingroup$
If it's a child object, and you can change the interface, can it not just take a raw pointer? The lifetimes should be well defined, and the child object probably shouldn't own it's parent. Otherwise, I'd still argue for a plain factory function. It's one function call, vs. one function call and multiple inheritance to add an intrusive deferral mechanism.
$endgroup$
– user673679
Dec 21 '18 at 12:01
add a comment |
$begingroup$
Identifiers with leading underscore(s) followed by a capital letter are reserved for the implementation and should not be used in your own code. It's easiest to just avoid leading underscores.
When using
enable_shared_from_this
it's important to use a static factory function and make the other constructors private. This prevents calling theExample
constructor directly (where callingshared_from_this
will be undefined behaviour, since we don't have ashared_ptr
).
Do we really need enable_shared_from_this
? The whole thing could be more easily written as:
class Example
{
private:
Example() { }
public:
static std::shared_ptr<Example> Create()
{
auto example = std::make_shared<Example>();
example->do_the_thing();
return example;
}
};
It really depends on what do_the_thing()
is...
If we have to register the class somewhere after creation (or consistently perform some action), perhaps that logic doesn't belong in the Example
class at all.
struct Example {};
struct Registry
{
template<class T, class... Args>
std::shared_ptr<T> CreateAndRegister(Args&&... args)
{
auto object = std::make_shared<T>(std::forward<Args>(args)...);
Register(object);
return object;
}
};
auto registry = Registry();
auto e = registry.CreateAndRegister<Example>();
While an object has control over it's own copy / move semantics, it generally shouldn't care who / what owns it.
So the question is: why does Example
need to "break the 4th wall" and know that it exists inside a shared_ptr
?
Large inheritance hierarchies are out of fashion nowadays (with good reason), but with a general solution, you may need to cope with:
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : ExampleA {}; // what if B wants to defer something?
and
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : enable_defer, enable_shared_from_this<ExampleB> {};
struct ExampleC : ExampleA, ExampleB {}; // uh oh... ?
shared_from_this
is quite complicated to use as it is with a class hierarchy.
$endgroup$
Identifiers with leading underscore(s) followed by a capital letter are reserved for the implementation and should not be used in your own code. It's easiest to just avoid leading underscores.
When using
enable_shared_from_this
it's important to use a static factory function and make the other constructors private. This prevents calling theExample
constructor directly (where callingshared_from_this
will be undefined behaviour, since we don't have ashared_ptr
).
Do we really need enable_shared_from_this
? The whole thing could be more easily written as:
class Example
{
private:
Example() { }
public:
static std::shared_ptr<Example> Create()
{
auto example = std::make_shared<Example>();
example->do_the_thing();
return example;
}
};
It really depends on what do_the_thing()
is...
If we have to register the class somewhere after creation (or consistently perform some action), perhaps that logic doesn't belong in the Example
class at all.
struct Example {};
struct Registry
{
template<class T, class... Args>
std::shared_ptr<T> CreateAndRegister(Args&&... args)
{
auto object = std::make_shared<T>(std::forward<Args>(args)...);
Register(object);
return object;
}
};
auto registry = Registry();
auto e = registry.CreateAndRegister<Example>();
While an object has control over it's own copy / move semantics, it generally shouldn't care who / what owns it.
So the question is: why does Example
need to "break the 4th wall" and know that it exists inside a shared_ptr
?
Large inheritance hierarchies are out of fashion nowadays (with good reason), but with a general solution, you may need to cope with:
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : ExampleA {}; // what if B wants to defer something?
and
struct ExampleA : enable_defer, enable_shared_from_this<ExampleA> {};
struct ExampleB : enable_defer, enable_shared_from_this<ExampleB> {};
struct ExampleC : ExampleA, ExampleB {}; // uh oh... ?
shared_from_this
is quite complicated to use as it is with a class hierarchy.
edited Dec 21 '18 at 12:18
answered Dec 21 '18 at 11:17
user673679user673679
2,6911926
2,6911926
$begingroup$
I generally agree that std::enable_shared_from_this is bad practice. In my use case, Example needs to register itself as a listener on a child object (that is created in the constructor as well) that takes a shared_ptr/weak_ptr. It's one of the few instances where I think it's appropriate, but I rather implement this general pattern than hard code it into the classes that needs it.
$endgroup$
– monoceres
Dec 21 '18 at 11:45
$begingroup$
If it's a child object, and you can change the interface, can it not just take a raw pointer? The lifetimes should be well defined, and the child object probably shouldn't own it's parent. Otherwise, I'd still argue for a plain factory function. It's one function call, vs. one function call and multiple inheritance to add an intrusive deferral mechanism.
$endgroup$
– user673679
Dec 21 '18 at 12:01
add a comment |
$begingroup$
I generally agree that std::enable_shared_from_this is bad practice. In my use case, Example needs to register itself as a listener on a child object (that is created in the constructor as well) that takes a shared_ptr/weak_ptr. It's one of the few instances where I think it's appropriate, but I rather implement this general pattern than hard code it into the classes that needs it.
$endgroup$
– monoceres
Dec 21 '18 at 11:45
$begingroup$
If it's a child object, and you can change the interface, can it not just take a raw pointer? The lifetimes should be well defined, and the child object probably shouldn't own it's parent. Otherwise, I'd still argue for a plain factory function. It's one function call, vs. one function call and multiple inheritance to add an intrusive deferral mechanism.
$endgroup$
– user673679
Dec 21 '18 at 12:01
$begingroup$
I generally agree that std::enable_shared_from_this is bad practice. In my use case, Example needs to register itself as a listener on a child object (that is created in the constructor as well) that takes a shared_ptr/weak_ptr. It's one of the few instances where I think it's appropriate, but I rather implement this general pattern than hard code it into the classes that needs it.
$endgroup$
– monoceres
Dec 21 '18 at 11:45
$begingroup$
I generally agree that std::enable_shared_from_this is bad practice. In my use case, Example needs to register itself as a listener on a child object (that is created in the constructor as well) that takes a shared_ptr/weak_ptr. It's one of the few instances where I think it's appropriate, but I rather implement this general pattern than hard code it into the classes that needs it.
$endgroup$
– monoceres
Dec 21 '18 at 11:45
$begingroup$
If it's a child object, and you can change the interface, can it not just take a raw pointer? The lifetimes should be well defined, and the child object probably shouldn't own it's parent. Otherwise, I'd still argue for a plain factory function. It's one function call, vs. one function call and multiple inheritance to add an intrusive deferral mechanism.
$endgroup$
– user673679
Dec 21 '18 at 12:01
$begingroup$
If it's a child object, and you can change the interface, can it not just take a raw pointer? The lifetimes should be well defined, and the child object probably shouldn't own it's parent. Otherwise, I'd still argue for a plain factory function. It's one function call, vs. one function call and multiple inheritance to add an intrusive deferral mechanism.
$endgroup$
– user673679
Dec 21 '18 at 12:01
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210108%2fdefer-pattern-for-constructors-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown