Могу ли я использовать boost :: make_shared с приватным конструктором? - PullRequest
7 голосов
/ 07 апреля 2010

Обратите внимание на следующее:

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

Похоже, что DirectoryIterator должен быть в состоянии вызвать boost::make_shared<DirectoryIteratorImpl>, потому что он друг DirectoryIteratorImpl.Однако этот код не удается скомпилировать, поскольку конструктор для DirectoryIteratorImpl является закрытым.

Поскольку этот класс является внутренней деталью реализации, которую клиенты DirectoryIterator никогда не должны трогать, было бы неплохо, если бы я мог сохранить конструктор в секрете.

Это мое основное недоразумение вокруг make_shared или мне нужно пометить какую-то часть усиления как friend для вызова компиляции?

Ответы [ 3 ]

5 голосов
/ 07 апреля 2010

Для этого вам действительно понадобится подружиться. В основном make_shared вызывает конструктор, и тот факт, что это делается из функции-друга, не имеет значения для компилятора.

Хорошая новость заключается в том, что make_shared вызывает конструктор, а не любую другую часть. Так что создание make_shared друга будет работать ... Однако это означает, что любой может создать shared_ptr<DirectoryIteratorImpl> ...

4 голосов
/ 07 апреля 2010

Есть ли веская причина не использовать старый добрый конструктор shared_ptr? (Если он есть, вы можете взглянуть на реализацию make_shared и сделать это)

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

Таким образом, вызов конструктора выполняется из класса DirectoryIterator, который уже является другом DirectoryIteratorImpl, не открывая дверь для всего остального кода.

0 голосов
/ 19 июля 2013

Вы можете разделить ваш класс на интерфейсную часть и часть реализации.Часть интерфейса становится общедоступной, а часть реализации может иметь открытые конструкторы.Однако это означает, что вы должны использовать виртуальное наследование.

...