How to make boost::make_shared a friend of my class

后端 未结 6 1318
借酒劲吻你
借酒劲吻你 2021-02-03 12:28

I have written a class with protected constructor, so that new instances can only be produced with a static create() function which returns shared_ptr\'s to my class. To provide

相关标签:
6条回答
  • 2021-02-03 13:10

    I would try without the template part. After all, you want a specific instantiation of the (template) function to be a friend of your class, aren't you? Does

    friend boost::shared_ptr<Connection> boost::make_shared(const ConnectionManagerPtr&, const std::string&);
    

    work?

    If that's not the solution, it might be helpful to give us the compiler messages you're getting ...

    0 讨论(0)
  • 2021-02-03 13:11

    I think that is not the right place to use make_shared. Just construct your object with operator new and pass the pointer to shared_ptr constructor. That way you don't need to be friends with anyone.

    BTW, why template arguments and function arguments are of different type?

    0 讨论(0)
  • 2021-02-03 13:15

    You don't need to template the friend part, but you need to signify that the friend function is a template:

    friend boost::shared_ptr<Connection> boost::make_shared<>(/* ... */);
    //                                                     ^^
    

    That works with Comeau and current GCC versions but fails with VC. Better would be the following form:

    friend boost::shared_ptr<Connection> boost::make_shared<Connection>(/* ... */);
    

    That works across multiple compilers now - i tested it on VC8, VC10, GCC 4.2, GCC 4.5 and Comeau 4.3.

    Alternatively using a qualified name to refer to a particular instance of the function template as Martin does should work and does with Comeau, but GCC chokes on it.

    A useful alternative that doesn't depend on the implementation details of make_shared() (and thus also works with VC10s TR1 implementation) is to use the pass-key-idiom for access-protection of the constructor and to befriend the create() function instead, e.g.:

    class Connection {
    // ...
    public:
        class Key {
            friend boost::shared_ptr<Connection> create(const ConnectionManagerPtr&, 
                                                        const std::string&);
            Key() {}
        };
        Connection(const ConnectionManagerPtr&, const std::string&, const Key&);
    };
    
    boost::shared_ptr<Connection> create(const ConnectionManagerPtr& p, 
                                         const std::string& s) 
    {
        return boost::make_shared<Connection>(p, s, Connection::Key());
    }
    
    0 讨论(0)
  • 2021-02-03 13:27

    I ended up using the below simple solution to enforce shared ownership. No friendship required.

    class probe {
        probe() = default;
        probe(...) { ... }
    
        // Part I of III, private
        struct creation_token {};
        probe(probe const&) = delete;
        probe& operator=(probe const&) = delete;
    
    public:
        // Part II of III, public
        template <class... Args>
        probe(creation_token&&, Args&&... args):
            probe(std::forward<Args>(args)...) {}
    
        // Part III of III, public
        template <class... Args>
        static auto create(Args&&... args) {
            return make_shared<probe>(creation_token(),
                std::forward<Args>(args)...);
        }
    };
    
    0 讨论(0)
  • 2021-02-03 13:27

    Just a summary of how a complete version may look like:

    #include <iostream>
    #include <boost/make_shared.hpp>
    
    class Foo {
      explicit Foo(int x) {
        std::cout << "Foo::Foo(" << x << ")\n";
      }
    public:
      friend boost::shared_ptr<Foo> boost::make_shared<Foo, int>(const int& x);
    
      static boost::shared_ptr<Foo> create(int x) {
        return boost::make_shared<Foo, int>(x);
      }
    
      ~Foo() {
        std::cout << "Foo::~Foo()\n";
      }
    };
    
    int main(int argc, const char *argv[]) {
      Foo::create(42);
    }
    
    0 讨论(0)
  • 2021-02-03 13:29

    Below are some macros I wrote up to do this for you. In your case, you would use:

    BOOST_MAKE_SHARED_2ARG_CONSTRUCTOR(Connection, const ConnectionManagerPtr&, const std::string&);
    

    Macro definitions:

    // Required includes
    #include <boost/make_shared.hpp>
    #include <boost/type_traits/add_reference.hpp>
    #include <boost/type_traits/add_const.hpp> 
    
    // Helper macro
    #define CONST_REFERENCE(T) boost::add_reference<boost::add_const<T>::type>::type
    
    /** BOOST_MAKE_SHARED_nARG_CONSTRUCTOR(CLASS_NAME, ARG1_TYPE, ARG2_TYPE, ...) 
      *
      * Use this macro inside the body of a class to declare that boost::make_shared
      * should be considered a friend function when used in conjunction with the
      * constructor that takes the given argument types.  This allows the constructor 
      * to be declared private (making it impossible to accidentally create an instance 
      * of the object without immediatly storing it in a boost::shared_ptr).  
      * Example usage:
      *
      * class Foo {
      *   private:
      *     Foo(int size, const char* name);
      *     MAKE_SHARED_2ARG_CONSTRUCTOR(Foo, int, const char*);
      * };
      * 
      * boost::shared_ptr<Foo> myFoo = boost::make_shared<Foo>(3, "Bob");
      *
      * Note that you need to explicitly specify the number of arguments 
      * that the constructor takes as part of the macro name.  Also, note that 
      * macros don't mix well with templated types that contain commas -- so 
      * if you have such a type, then you should typedef it to a shorter name 
      * before using it with this macro.
      */
    #define BOOST_MAKE_SHARED_0ARG_CONSTRUCTOR(CLASS_NAME) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>()
    #define BOOST_MAKE_SHARED_1ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1))
    #define BOOST_MAKE_SHARED_2ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2))
    #define BOOST_MAKE_SHARED_3ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3))
    #define BOOST_MAKE_SHARED_4ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4))
    #define BOOST_MAKE_SHARED_5ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5))
    #define BOOST_MAKE_SHARED_6ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5), CONST_REFERENCE(ARG_TYPE6))
    #define BOOST_MAKE_SHARED_7ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6, ARG_TYPE7) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5), CONST_REFERENCE(ARG_TYPE6)), CONST_REFERENCE(ARG_TYPE7))
    #define BOOST_MAKE_SHARED_8ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6, ARG_TYPE7, ARG_TYPE8) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5), CONST_REFERENCE(ARG_TYPE6)), CONST_REFERENCE(ARG_TYPE7)), CONST_REFERENCE(ARG_TYPE8))
    #define BOOST_MAKE_SHARED_9ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6, ARG_TYPE7, ARG_TYPE8, ARG_TYPE9) \
        friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5), CONST_REFERENCE(ARG_TYPE6)), CONST_REFERENCE(ARG_TYPE7)), CONST_REFERENCE(ARG_TYPE8)), CONST_REFERENCE(ARG_TYPE9))
    
    0 讨论(0)
提交回复
热议问题