Can I use boost::make_shared with a private constructor?

喜欢而已 提交于 2019-11-27 06:08:45

问题


Consider the following:

class DirectoryIterator;

namespace detail {
    class FileDataProxy;

    class DirectoryIteratorImpl
    {
        friend class DirectoryIterator;
        friend class FileDataProxy;

        WIN32_FIND_DATAW currentData;
        HANDLE hFind;
        std::wstring root;

        DirectoryIteratorImpl();
        explicit DirectoryIteratorImpl(const std::wstring& pathSpec);
        void increment();
        bool equal(const DirectoryIteratorImpl& other) const;
    public:
        ~DirectoryIteratorImpl() {};
    };

    class FileDataProxy //Serves as a proxy to the WIN32_FIND_DATA struture inside the iterator.
    {
        friend class DirectoryIterator;
        boost::shared_ptr<DirectoryIteratorImpl> iteratorSource;
        FileDataProxy(boost::shared_ptr<DirectoryIteratorImpl> parent) : iteratorSource(parent) {};
    public:
        std::wstring GetFolderPath() const {
            return iteratorSource->root;
        }
    };
}

class DirectoryIterator : public boost::iterator_facade<DirectoryIterator, detail::FileDataProxy, std::input_iterator_tag>
{
    friend class boost::iterator_core_access;
    boost::shared_ptr<detail::DirectoryIteratorImpl> impl;
    void increment() {
        impl->increment();
    };
    bool equal(const DirectoryIterator& other) const {
        return impl->equal(*other.impl);
    };
    detail::FileDataProxy dereference() const {
        return detail::FileDataProxy(impl);
    };
public:
    DirectoryIterator() {
        impl = boost::make_shared<detail::DirectoryIteratorImpl>();
    };
};

It seems like DirectoryIterator should be able to call boost::make_shared<DirectoryIteratorImpl>, because it is a friend of DirectoryIteratorImpl. However, this code fails to compile because the constructor for DirectoryIteratorImpl is private.

Since this class is an internal implementation detail that clients of DirectoryIterator should never touch, it would be nice if I could keep the constructor private.

Is this my fundamental misunderstanding around make_shared or do I need to mark some sort of boost piece as friend in order for the call to compile?


回答1:


You will indeed need to make some boost pieces friend for this. Basically make_shared is calling the constructor and the fact that this is done from within a friend function does not matter for the compiler.

The good news though is that make_shared is calling the constructor, not any other piece. So just making make_shared friend would work... However it means that anyone could then create a shared_ptr<DirectoryIteratorImpl>...




回答2:


Is there a good reason not to use the good old shared_ptr constructor? (If there is one, you might want to take a look at the make_shared implementation and do it)

DirectoryIterator()
   : impl( new detail::DirectoryIteratorImpl() )
{}

This way the call to the constructor is made from the DirectoryIterator class that is already a friend of DirectoryIteratorImpl without opening the door for all other code.




回答3:


You can split your class into interface part and implementation part. The interface part is made public, and the implementation part can have public constructors. However, that means you have to use virtual inheritance.



来源:https://stackoverflow.com/questions/2590310/can-i-use-boostmake-shared-with-a-private-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!