【问题标题】:std::reverse on boost::ptr_vector slices objects?std::reverse 对 boost::ptr_vector 切片对象?
【发布时间】:2014-07-19 15:35:53
【问题描述】:

BaseDerived 成为具有数据成员的类:

class Base {
public:
    Base(int i):f(i)     { }
    virtual void print() { cout << "base " << f << endl; }
    int f;
};

class Derived: public Base {
public:
    Derived(int i):Base(0),g(i) {  }
    void print() { cout << "derived " << g << endl; }
    int g;
};

现在在堆上创建BaseDerived 的一些实例并将它们存储在boost::ptr_vector 中:

int main(int argc, char *argv[])
{
    boost::ptr_vector<Base> v;
    v.push_back(new Derived(1));
    v.push_back(new Base(2));
    v.push_back(new Base(3));
    v.push_back(new Derived(4));

打印所有对象:

    for (std::size_t i(0); i != v.size(); ++i)
        v[i].print();

然后反转并再次打印:

    std::reverse(v.begin(), v.end());
    for (std::size_t i(0); i != v.size(); ++i)
        v[i].print();
}

这个程序打印:

derived 1
base 2
base 3
derived 4
derived 1
base 3
base 2
derived 4

std::reverse() on boost::ptr_vector 调用 std::iter_swap(),后者又调用 std::swap,后者通过创建临时副本来交换项目。

但是,临时副本确实对派生对象进行了切片。如您所见,Derived 对象 1 和 4 中的int g没有交换,因此交换后对象被破坏。

这种行为让我很困惑。 boost::ptr_vector 不是一个容器来避免这种问题吗?

我需要的是一个虚拟复制构造函数,它在 C++ 中不存在。

我该如何解决这个问题?是否需要为Base实现一个虚拟交换函数,以便虚拟调度调用Derived的另一个交换成员函数?

编辑:为什么首先要复制对象?由于向量只存储指针,因此反转它应该是指针的交换,而不是指向的对象! 有这样的功能吗?

【问题讨论】:

  • 根据适用于变异算法的 Ptr 容器的常见问题解答,“任何通过交换元素来移动元素的变异算法。”
  • 是的,但是 ptr_vector 的元素是指针,而不是对象。所以它应该交换指针,而不是交换和切片对象。
  • 它变得更好:boost.org/doc/libs/1_55_0/libs/ptr_container/doc/… 说“算法可作为成员函数使用”。事实上,有一个 boost::ptr_vector::reverse()。但是当我调用它时,我得到一个编译错误:'std::vector >'中没有​​名为'reverse'的成员
  • “虚拟复制构造函数”在 ptr_container 中处理,带有“可克隆”概念——非成员 new_clonedelete_clone boost.org/doc/libs/1_55_0/libs/ptr_container/doc/…
  • 请考虑vector&lt;unique_ptr&lt;T&gt;&gt;

标签: c++ std swap boost-ptr-container


【解决方案1】:

Boost 的ptr_vector 类包含成员函数,其工作是操作底层指针。但是公共接口很大程度上隐藏了向量内部存储指针的事实。这个想法是产生一些表现得好像它直接包含对象但在内部存储指针以避免在将对象放入容器时切片的东西。但是如果你将一个对象从容器中复制到一个基本类型的对象中,那么它就会切片。所以你不能在ptr_vectors 上调用这样的函数。

不幸的是,这意味着在将任何算法应用于 ptr_vector 之前,您需要准确了解它的作用。

【讨论】:

    【解决方案2】:

    一种可能的解决方法是使用

    std::reverse(v.base().begin(), v.base().end());
    

    相反。它反转指针而不是自间接迭代器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-18
      • 1970-01-01
      • 2011-01-30
      • 2018-02-24
      • 1970-01-01
      相关资源
      最近更新 更多