jeudi 9 juin 2022

Force the users to create an new instance by call a method which returns a shared_ptr of the class itself

I hope to prevent the users from creating new instance through the constructor, so I mark the constructor as a private method.

What's more, I need to provide a method to return an object which is used to automatically manage the life of the instance.The function in the code snippet below is getFoo().

Here is the code snippet which I wrote at first:

#include <iostream>
#include <memory>
 
class Foo : public std::enable_shared_from_this<Foo> {
private:     //the user should construct an instance through the constructor below.                    
    Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }
public:
    ~Foo() { std::cout << "Foo::~Foo\n"; } 
    std::shared_ptr<Foo> getFoo() { return shared_from_this(9); }
private:
    int num_;
};

Since the constructor is marked as private, so there is no way to create an instance, which causes getFoo could never be called. So I updated the code snippet above.

Here is the code snippet:

#include <iostream>
#include <memory>
 
class Foo : public std::enable_shared_from_this<Foo> {
private:     //the user should construct an instance through the constructor below.                    
    Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }
public:
    ~Foo() { std::cout << "Foo::~Foo\n"; } 
static std::shared_ptr<Foo> Create() { return std::make_shared<Foo>(5); }
private:
    int num_;
};
 
int main() {
    auto pf = Foo::Create(); 
}

But it does not compile, indeed. Here is what the compiler complains:

In  file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/alloc_traits.h:33,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/ext/alloc_traits.h:34,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/basic_string.h:40,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/string:53,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/ios:42,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/ostream:38,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_construct.h: In instantiation of 'void std::_Construct(_Tp*, _Args&& ...) [with _Tp = Foo; _Args = {int}]':
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/alloc_traits.h:635:19:   required from 'static void std::allocator_traits<std::allocator<void> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = Foo; _Args = {int}; allocator_type = std::allocator<void>]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/shared_ptr_base.h:604:39:   required from 'std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args = {int}; _Tp = Foo; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/shared_ptr_base.h:971:16:   required from 'std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = Foo; _Alloc = std::allocator<void>; _Args = {int}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/shared_ptr_base.h:1712:14:   required from 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {int}; _Tp = Foo; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/shared_ptr.h:464:59:   required from 'std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {int}; _Tp = Foo]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/shared_ptr.h:1009:14:   required from 'std::shared_ptr<typename std::enable_if<(! std::is_array< <template-parameter-1-1> >::value), _Tp>::type> std::make_shared(_Args&& ...) [with _Tp = Foo; _Args = {int}; typename enable_if<(! is_array< <template-parameter-1-1> >::value), _Tp>::type = Foo]'
<source>:9:68:   required from here
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_construct.h:119:7: error: 'Foo::Foo(int)' is private within this context
  119 |       ::new((void*)__p) _Tp(std::forward<_Args>(__args)...);
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:6:5: note: declared private here
    6 |     Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }
      |     ^~~

It really surprises that Create() could not call the private constructor. I think any member function should have the allowance to invoke another private member variable. If I miss something, please let me know.

Note: I only could use C++11.

Five minutes later, I realise where am I wrong. Create() is not a member function, it's a static function. It's legal that it could not call the non-static member function :(

Aucun commentaire:

Enregistrer un commentaire