C++ 将std::vector的副本附加到其自身的末尾

C++ 将std::vector的副本附加到其自身的末尾,c++,gcc,iterator,clang,llvm,C++,Gcc,Iterator,Clang,Llvm,我试图复制字符串的向量,并将其附加到原始向量的末尾,即复制其内容。例如: Input : vector<string> s = {"abc", "def"} Output: vector<string> s = {"abc", "def", "abc", "def"} 但是,这会显示编译器相关的结果。最后,它给了我预期的答案 它给了我 Output: vector<string> s = {"abc", "def", "", ""} 输出:向量s={

我试图复制字符串的向量,并将其附加到原始向量的末尾,即复制其内容。例如:

 Input : vector<string> s = {"abc", "def"}
 Output: vector<string> s = {"abc", "def", "abc", "def"}
但是,这会显示编译器相关的结果。最后,它给了我预期的答案

它给了我

 Output: vector<string> s = {"abc", "def", "", ""}
输出:向量s={“abc”,“def”,“”“,”“}
我想知道为什么会发生这种情况,实现这一矢量复制目标最安全的方法是什么


这是上面程序的ideone.com链接:

如前所述,您似乎只需拨打
reserve

sv.reserve(sv.size() * 2);
这是因为如果发生重新分配,迭代器将失效。您可以自己检查:

std::cout << sv.capacity() << "\n"; // 2

std::cout虽然可以使用迭代器完成,但安全的替代方法是避免使用迭代器:

size_t size = v.size();  // Of course we shouldn't access .size() in the loop...
v.reserve(size * 2);     // Preallocation. Thanks @Ali for this performance hint
for (size_t i = 0; i < size; ++i)
    v.push_back(v[i]);
size\u t size=v.size();//当然,我们不应该访问循环中的.size()。。。
v、 保留区(大小*2);//预分配。感谢@Ali提供此性能提示
对于(大小i=0;i

通常,使用迭代器同时修改数据结构(不仅是其元素)是危险的;您应该仔细阅读迭代器何时失效,以及修改后重用旧迭代器何时安全。因此,有时使用“old”方法迭代随机访问序列是有意义的:使用索引变量。

也可以这样做

vector<string> data = {"abc", "def"}; // Input String Vector
int len = data.size();
for(int i = 0; i < len; i++)
{
    data.push_back(data[i]); // Making Copy of String Vector
}

vector<string> data = {"abc", "def", "abc", "def"};
//Resultant String Vector
矢量数据={“abc”,“def”};//输入字符串向量
int len=data.size();
对于(int i=0;i
正如其他人已经指出的,您需要通过调用确保向量在插入过程中不会重新分配。(如果选择使用
push_back()
将元素放入向量中,那么调用reserve也是一个好主意。)

然后仍然存在迭代器无效问题(详见下文),但据我所知,下面的代码忽略了这一点:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

using namespace std;

int main() {

  vector<string> s{"abc", "def"};

  auto size = s.size();

  s.reserve(2*size); // <-- This one is essential to ensure
                     //     no reallocation during insertion

  const string* first = s.data(); // using pointer, instead of iterator

  copy(first, first+size, back_inserter(s));

  for (const auto& e : s)
    cout << e << '\t';

  cout << endl;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
int main(){
向量s{“abc”,“def”};
自动大小=s.大小();

s、 保留区(2*尺寸);//如果迭代器无效,则看起来像UB。调用
reserve
以保证不验证。您使用的是哪个版本的g++呢?使用g++4.8.1,我得到了正确的输出。我使用的是相同的g++4.8.1。我已附加到联机编译器的链接以显示问题。@KerrekSB这真的有保证吗?我认为任何插入或删除会使迭代器无效(这意味着不能保证迭代器仍然有效,尽管它们可以有效)@阿里:有意思;我看不到任何明显的东西。你在利用向量的存储是连续的这一事实……据我所知,结束迭代器可能仍然无效。@Kit也许那只是用于
push\u back
。但我不是专家。不幸的是,结束迭代器被任何插入都无效,即使在结束时也是如此,即使没有重新分配。那是因为它在插入点之后。因此,尽管我认为没有任何严重的原因说明它不应该定义行为,但使用结束迭代器定义插入的范围是不正确的(AFAIK)定义的行为。@SteveJessop请检查我的答案。这会调用UB吗?@Ali:不确定。根据标准,指针
first+size
是无效的,但你可能会认为这只是意味着它不能再被用来访问元素了(以前不是,它是一个非结束指针)。在实践中肯定是“无效的”从
向量的角度来看
无法神奇地使指针不再与其他指针相等:-)来自cppreference.com:“过去的结束迭代器也无效。”@leems感谢检查。但是,请注意
s.data()
生成的是指针,而不是迭代器。因此
s.data()+s.size()
并不等同于
s.end()
。哦,我读你的代码太快了。在这种情况下,它可能确实有效。@leems是的,这也经常发生在我身上。:(更新了代码,明确了类型,并添加了注释。希望下一个快速阅读者不会错过要点(er).刚刚检查并回答了;谢谢你的提示,如果你确定会有多少次插入,那么强制预分配确实是一个好主意。你认为如何使用迭代器来完成它?
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

using namespace std;

int main() {

  vector<string> s{"abc", "def"};

  auto size = s.size();

  s.reserve(2*size); // <-- This one is essential to ensure
                     //     no reallocation during insertion

  const string* first = s.data(); // using pointer, instead of iterator

  copy(first, first+size, back_inserter(s));

  for (const auto& e : s)
    cout << e << '\t';

  cout << endl;
}