【问题标题】:Container that stores a mixture of base and derived objects?存储基础对象和派生对象的混合容器?
【发布时间】:2012-09-02 08:58:05
【问题描述】:

什么是正确的做法?我知道如果容器是基类值类型,那么存储的派生对象是“切片”的。如果容器是派生类类型,则不能存储基类对象。对吧?

如果使用指针,auto_ptr 不能使用,因为它有复制语义问题。 shared_ptr 是解决此问题的唯一解决方案吗?

谁能提供更多详细信息、示例代码或解决此问题的在线文章?这应该是一个很常见的问题,但是我在教科书或网上没有找到太多关于它的信息。

提前致谢。

顺便说一句,我只是在 unique_ptr 上搜索。它似乎不支持复制语义。那么在STL中使用不是只比auto_ptr安全,而是可能由于缺乏复制语义,许多STL操作或算法不能在unique_ptr的容器上使用?

【问题讨论】:

    标签: c++ inheritance


    【解决方案1】:

    如果您想要多态行为(并且确实想要),那么您必须使用指针或引用。这在很多地方都有很好的记录。

    因为你不能使用引用容器,你必须使用指针容器。

    现在,您可以使用任何您认为合适的指针类型:unique_ptrshared_ptr 或原始指针。

    【讨论】:

    • 确实不能创建引用容器。但是你可以用std::reference_wrapper<T> 伪造它。它包含一个指针,但允许您通过引用访问它。
    • 有没有办法知道算法是否可以安全地与unique_ptr一起使用?显然有些不能(copy()fill()),但似乎有些只是删除或重新排列元素可能会或可能不会,这取决于它们的实现方式。
    • @PeteBecker:我尝试了reference_wrapper 的容器一次,但效果不佳。问题是在 C++ 中你不能重载operator.,所以为了访问包含的对象的成员你必须做,例如c[0].get()->member。如果你必须这样做,你也可以这样做c[0]->member
    【解决方案2】:

    最明显的解决方案是使用std::unique_ptr

    class IBase {};
    class Derived : virtual public IBase {};
    std::vector<std::unique_ptr<IBase>> v;
    v.push_back(std::unique_ptr<IBase>(new Derived())); 
    

    您可以使用std::shared_ptr,但它的所有权语义显着改变了程序的行为,使动态分配的对象保持活动状态,直到没有人持有对它们的引用。

    【讨论】:

    • 感谢 juanchopanza,您能否详细说明“但所有权语义显着改变了程序的行为,保持 ...”?你的意思是如果程序员不太小心,使用 shared_ptr 有时会留下未使用的副本,因此对象不会及时释放;而 unique_ptr 总是只有一个副本并且没有这样的问题?
    • @user1559625 this SO question 可以提供帮助。基本上,unique_ptr 拥有指针对象的所有权,并在它被删除时将其删除。所有权可以从一个 unique_ptr “移动”到另一个,但不能有多个所有者。使用 shared_ptr,可以有任意数量的所有者,最后一个死去删除指针对象。有时,您想确切地知道指针何时被删除,而其他时候您并不关心。
    • 我认为IBase 必须有一个虚拟析构函数。对于shared_ptr,这不是问题,因为删除器的类型擦除;但unique_ptr 并非如此。
    • 但是如何从中取回原始对象?
    【解决方案3】:

    有 std::vector 和 std::shared_ptr 的例子。我想这就是你想要的。

    #include <iostream>
    #include <memory>
    #include <vector>
    
    class Base {
    public:
       virtual void foo() {
          std::cout << "base" << std::endl;
       }
    };
    
    class Derived : public Base {
       void foo() {
          std::cout << "derived" << std::endl;
       }
    };
    
    int main()
    {
       std::vector<std::shared_ptr<Base> > v;
       v.push_back(std::shared_ptr<Base>(new Base));
       v.push_back(std::shared_ptr<Base>(new Derived));
    
       for (auto it : v) {
          it->foo();
       }
    }
    

    【讨论】:

    • 不清楚这里是否需要共享所有权。我会说最好使用唯一所有权除非明确关心共享。
    • 我的问题也是,那么什么时候必须共享所有权?
    【解决方案4】:

    [http://www.boost.org/doc/libs/1_51_0/libs/ptr_container/doc/ptr_container.html](Boost 指针容器库)就是为此而生的。

    【讨论】:

    • 谢谢 n.m.非常有用的信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多