2010-04-07 76 views
7

考虑以下几点:我可以使用boost :: make_shared和一个私有构造函数吗?

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以便调用编译?

+0

你确定你需要shared_ptr的为您实现了一套指针? boost :: scoped_ptr通常更合适,使事情变得更简单。如果您希望DirectoryIterator是可复制的,并且副本应共享单个impl实例,则通常只会在此情况下使用Shared_ptr。在您发布的代码中,似乎共享impl的副本将是一个错误。 Shared_ptr用于多个指针应共享实例的所有权。 – Alan 2010-04-08 16:17:44

回答

5

你确实需要做一些提升作品的朋友这一点。基本上make_shared正在调用构造函数,并且这是从朋友函数内部完成的事实,对编译器无关紧要。

好消息是,虽然make_shared被调用构造函数,而不是其他任何作品。所以只是让make_shared朋友会工作......然而,这意味着任何人都可以再创建一个shared_ptr<DirectoryIteratorImpl> ...

+1

嗯...这是讨厌的地狱:)谢谢! – 2010-04-07 13:32:20

+0

'make_shared'的问题是它分配了一块内存,然后使用放置'new',这就是为什么它必须自己调用构造函数。我同意你的问题很烦人。 – 2010-04-07 13:59:35

+1

这样做的问题是,如果您迁移到TR1或C++ 0x,或者即使增强版发布更新,也无法保证它仍能正常工作。 – dvide 2010-04-07 17:19:32

4

是否有一个很好的理由不使用好老shared_ptr构造? (如果有一个,你可能想看看make_shared实现做)

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

这样调用构造函数从DirectoryIterator类所做的已经是DirectoryIteratorImpl的朋友不开放所有其他代码的大门。

+0

不,它没有任何问题。但我被告知使用'make_shared'在http://stackoverflow.com/questions/2569046/is-there-a-way-to-increase-the-efficiency-of-shared-ptr-by-storing-the-参考/ 2569211#2569211。我现在所做的只是按照你的建议完成。 +1 – 2010-04-07 13:31:16

+1

'make_shared'在其内存分配方面效率更高......(更少碎片化,更高速度) – 2010-04-07 13:58:21

+1

我知道内存碎片(你应该真的测量一下),但我有时会读到(实际上是在这里):*他谁牺牲正确的表现不值得*,这是一个很好的座右铭。而在最初的相关问题中,比利承认他不需要表演。如果构造函数是私有的,'make_shared'不应该是朋友(通过允许任何人通过'make_shared'构造对象来打破封装) – 2010-04-07 15:06:31

0

您可以将类分成接口部分和实现部分。 接口部分公开,实现部分可以有公共构造函数。 但是,这意味着你必须使用虚拟继承。

相关问题