【问题标题】:Does putting data into std::vector in C++ create a copy of the data?在 C++ 中将数据放入 std::vector 是否会创建数据的副本?
【发布时间】:2011-03-13 16:26:42
【问题描述】:

如果创建一个新的std::vector(或调用它的assign 方法)会创建数据的副本,我是否感兴趣?

例如,

void fun(char *input) {
    std::vector<char> v(input, input+strlen(input));
    // is it safe to assume that the data input points to was COPIED into v?
}

【问题讨论】:

  • 为什么不更改input[0] 并打印出v 以自己查找?
  • BlueRaja,我不知道如何测试它。感谢您的评论。
  • 添加了一个示例,说明如何检查自己对我的回答。

标签: c++ vector copying


【解决方案1】:

是的。元素总是被复制进或复制出 STL 容器。 (至少在 C++0x 中添加移动语义之前)

编辑:以下是您可以测试复制自己的方法:

#include <vector>
#include <iostream>

class CopyChecker
{
public:
    CopyChecker()
    {
        std::cout << "Hey, look! A new copy checker!" << std::endl;
    }
    CopyChecker(const CopyChecker& other)
    {
        std::cout << "I'm the copy checker! No, I am! Wait, the"
            " two of us are the same!" << std::endl;
    }
    ~CopyChecker()
    {
        std::cout << "Erroap=02-0304-231~No Carrier" << std::endl;
    }
};

int main()
{
    std::vector<CopyChecker> doICopy;
    doICopy.push_back(CopyChecker());
}

输出应该是:

嘿,看!新的副本检查器!
我是副本检查员!不,我是!等等,我们两个是一样的!
Erroap=02-0304-231~无运营商
Erroap=02-0304-231~无载体

【讨论】:

  • 那么在 C++0x 中会发生什么?这样的代码会中断吗?或者会有一个特殊的“移动语义”构造?
  • @bodacydo:在 C++0x IIRC 中,允许将元素移动到向量中而不是复制。这是性能优化。例如,如果您有一个字符串,您的对象可以只将指向该字符串的指针复制到容器中,而不是复制整个字符串本身。您的类型需要有一个移动构造函数来启用 C++0x 中的新行为。
  • @Billy ONeal:您还需要使用std::move 来使用移动语义。右值引用参数只绑定到临时变量。
  • 比利,感谢您的解释。非常感激。你的例子也很有趣。 :)
  • @bodacydo:没问题 :) 谢谢!
【解决方案2】:

元素总是被复制进或复制出 STL 容器。

虽然元素可能只是一个指针,在这种情况下,指针被复制而不是底层数据

【讨论】:

  • 另外,当元素类型是指针时,向量销毁不会对每个指针指向的数据做任何事情——它只是将指针设置为零或一些垃圾。这意味着需要注意存储在向量中的对象指针。另外,如果指针的所有权没有明确定义,则存在双重删除的额外风险。好处当然是速度。
  • @rwong:当指针向量被破坏时,为什么向量会将它们的值设置为任何值?它们即将不复存在。
  • 那我错了。我只想说,如果元素类型是指针,则不会自动清理。
【解决方案3】:

关于移动语义,如果您愿意,可以在 C++0x 中移动内容:

void fun_move(char *input)
{
    std::vector<char> v;
    auto len = strlen(input);
    v.reserve(len);
    std::move(input, input+len, std::back_inserter(v));
}

【讨论】:

  • 是 C++1x 了吗?目前看来,0x 的乐观情绪是没有根据的。 ;)
【解决方案4】:

如果您想移动数据,请使用std::swap_ranges,但您必须先分配内存:

vector<T> v;
v.reserve(std::distance(beg, end));
std::swap_ranges(beg, end, v.begin());

【讨论】:

  • 第一行默认构造一个 T 然后复制构造 n 次——这对我来说似乎不是很高效......
  • 现在你有未定义的行为。您需要在这里使用back_inserter,就像 FredOverflow 的答案中显示的那样。
【解决方案5】:

如果您不希望对象复制语义,那么您可以创建一个指向对象的向量,以便仅复制指针。但是,您必须确保指针在容器的生命周期内保持有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-25
    • 2021-08-13
    • 1970-01-01
    • 1970-01-01
    • 2016-10-24
    相关资源
    最近更新 更多