Defer pattern for constructors in C++












4












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










share|improve this question











$endgroup$

















    4












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










    share|improve this question











    $endgroup$















      4












      4








      4





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










      share|improve this question











      $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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Dec 21 '18 at 10:13







      monoceres

















      asked Dec 21 '18 at 10:05









      monoceresmonoceres

      1212




      1212






















          1 Answer
          1






          active

          oldest

          votes


















          4












          $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 the Example constructor directly (where calling shared_from_this will be undefined behaviour, since we don't have a shared_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.






          share|improve this answer











          $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











          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
          });


          }
          });














          draft saved

          draft discarded


















          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









          4












          $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 the Example constructor directly (where calling shared_from_this will be undefined behaviour, since we don't have a shared_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.






          share|improve this answer











          $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
















          4












          $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 the Example constructor directly (where calling shared_from_this will be undefined behaviour, since we don't have a shared_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.






          share|improve this answer











          $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














          4












          4








          4





          $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 the Example constructor directly (where calling shared_from_this will be undefined behaviour, since we don't have a shared_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.






          share|improve this answer











          $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 the Example constructor directly (where calling shared_from_this will be undefined behaviour, since we don't have a shared_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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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


















          • $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


















          draft saved

          draft discarded




















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          If I really need a card on my start hand, how many mulligans make sense? [duplicate]

          Alcedinidae

          Can an atomic nucleus contain both particles and antiparticles? [duplicate]