【问题标题】:How do STL containers copy objects?STL 容器如何复制对象?
【发布时间】:2009-11-07 13:35:54
【问题描述】:

我知道像 vector 这样的 STL 容器会在添加对象时复制它。 push_back 方法看起来像:

void push_back ( const T& x );

我很惊讶地看到它把项目作为参考。我写了一个示例程序来看看它是如何工作的。

struct Foo
{
    Foo()
    {
        std::cout << "Inside Foo constructor" << std::endl;
    }

    Foo(const Foo& f)
    {
        std::cout << "inside copy constructor" << std::endl;
    }
};

Foo f;
std::vector<Foo> foos;
foos.push_back(f);

这会复制对象,我可以看到它正在调用 copy-constructor

我的问题是,当push_back 将项目作为参考时,它是如何调用复制构造函数的?还是我在这里遗漏了什么?

有什么想法吗?

【问题讨论】:

    标签: c++ stl constructor


    【解决方案1】:

    它可能使用“placement new”在其内部数组中就地构造对象。放置new 不分配任何内存;它只是将对象放置在您指定的位置,然后调用构造函数。语法是new (address) Class(constructor_arguments)

    复制构造函数T::T(T const &amp;) 被调用以就地创建副本。像这样(简化):

    template<T>
    void vector<T>::push_back(T const &item) {
        // resize if necessary
        new (&d_array[d_size++]) T(item);
    }
    

    注意T 必须有一个复制构造函数才能工作。默认情况下(如果您什么都不做),它会免费获得一个。如果你明确定义它,它必须是publicvector&lt;T&gt; 才能工作。

    Here's how GNU's libstdc++ does it,但我怀疑它是否会很有启发性。有一个分配器(vector 的第二个模板参数)使它不那么简单。

    【讨论】:

    • 当 T 有一个无参数的构造函数时这是可以的。但是当它有一个参数化的构造函数时会发生什么?向量如何初始化新对象?
    • 当 T 有一个 复制构造函数 时这是可以的。默认情况下,如果你实现它,除非你明确地将它设为privateprotected
    • 谢谢。我会进一步调查。
    • 你的解释很清楚。我想知道,为什么他们没有像push_back(T const item) 这样的签名并避免放置新的位置。
    • 这将在项目被传递到函数时复制项目(因为它是按值传递),而按引用传递版本则避免了这种情况。它可以通过使用= 运算符来避免放置new,但这需要在那个位置已经有一个初始化对象(调用operator=),因此需要T 有一个默认构造函数。
    【解决方案2】:

    为了提高效率,C++ SDK 总是将const T &amp; 作为函数参数。

    在您的情况下,如果它以T 作为参数,则复制操作将执行两次,一次用于将其传递给函数push_back(f),一次用于内部将其添加到容器中。而将const T&amp;作为参数只需要一份!

    【讨论】:

      【解决方案3】:

      它使用placement new 运算符并将其复制构造到未初始化的内存中;

      placement new 在内存中的指定地址创建一个新元素,在向量的情况下,当前的 end();

      void push_back(const T& val){
      ::new (&*end()) T(val);
      [increase end]
      }
      

      查看http://spotep.com/dev/devector.h,它的代码非常清晰(与大多数 STL 实现相反)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-08
        • 1970-01-01
        • 2021-03-18
        • 2012-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-15
        相关资源
        最近更新 更多