如何高效地将std::vector<char>复制到std::string中?

6

这个问题是与如何有效地将std::string复制到vector中相反的一面
我通常这样复制向量(空终止字符串)

std::string s((char*)&v[0]);

或者(如果字符串已经被声明)像这样
s = (char*)&v[0];

虽然它能完成工作,但也许有更好的方法。

编辑

据说C风格的强制类型转换很丑陋,那么这个怎么样?

s = reinterpret_cast<char*>(&vo[0]);

1
不需要强制转换。&v[0] 产生一个 char;std::string 有一个以 const char 为参数的构造函数;将 char* 转换为 const char* 不需要强制转换。 - Gnawme
3个回答

15

只需使用迭代器构造函数:

std::string s(v.begin(), v.end());

(编辑):或者使用字符指针加大小的构造函数:

std::string s(v.data(), v.size());   // or &v[0]

如果您的字符串以空字符结尾并且希望省略终止符,则可以使用char*构造函数:

std::string s(v.data());             // or &v[0]

更新: 正如 @Dave 所说,您可以使用相同的语法对现有字符串进行赋值

s.assign(v.begin(), v.end());
s.assign(v.data(), v.size());  // pointer plus size
s.assign(v.data());            // null-terminated

3
请使用assign成员函数,它可以接收与构造函数相同的参数。 - Dave S
@Dave,你能否改进一下这个答案呢?因为这个用例很重要。 - karimjee
我添加了赋值语法。谢谢,Dave! - Kerrek SB
@bdonlan:确实。如果您知道大小,那么迭代器构造或char指针加大小是更好的选择。 - Kerrek SB
@Kerrek SB 在这里你把我弄丢了。如果你知道大小,那么迭代器构造更好?但是我在你的回答中没有看到任何对size的调用。 - karimjee
显示剩余6条评论

11
std::string s( &v[ 0 ] );

在Visual C++ 2005中,生成的汇编代码行数不到一半

std::string s( v.begin(), v.end() );

@karimjee:汇编代码的行数是效率的一个具体衡量标准。从这个角度来看,你已经做得非常高效了。我怀疑 s(&v[0], v.length()) 可能更高效(也更安全),但我现在离开了我的Windows机器... - Gnawme
1
生成的汇编代码的行数可能是具体的,但它很少有任何真实用途。在上面的示例中,我仍然会使用第二个版本,因为它更有效率(因为它已经知道字符串的大小并且可以预分配空间)。 - Martin York
@Tux-D:上次我检查时,execution_time = #_instructions_executed * cycles_per_instruction * clock_cycle_time,所以执行指令更少的东西将会更快地执行,并且从这个角度来看更有效率。记住软件工程第一法则——“每个软件工程师都应该大致知道他们的代码生成了什么汇编语言。” - Gnawme
1
Visual Studio 2005,发布模式,/O2 -- std::string onoc( &ono[ 0 ], ono.size() );: 19行汇编,1个构造函数调用std::string onos( ono.begin(), ono.end() );: 30行汇编,2个构造函数调用。关注代码设计和编码决策所产生的后果以及编译器优化的影响,是成为专业编码人员的一部分(特别是在嵌入式/移动领域)。 - Gnawme
@Omnifarious:不错。不幸的是,在C++03中没有vector::data(),但我猜&vec[0]并不会更慢,并且很可能是data()在底层执行的操作。 - Gnawme
显示剩余7条评论

1
s.resize( v.size() );
std::copy( v.begin(), v.end(), s.begin() );

你可能会问为什么...因为一旦那些该死的编译器创建者理解了标准化的力量,这种方法将比任何其他方式更快...

而且说实话:

std::string( (char*)v.data(), v.size() );
s.assign( (char*)v.data(), v.size() );

...可能更安全,而不会失去效率。


::std::copy 方法在调用 s.resize(); 之前是无法正常工作的。 - Omnifarious
@Kornel,我认为你的std::copy答案非常好。你觉得把它作为“正式”的答案如何? - karimjee
你的答案更好,因为它不依赖于构造函数或分配,而是知道你正在提供随机访问迭代器。虽然 C 风格的转换仍然很丑陋。 - Omnifarious
“copy”选项生成最明显高效的代码。其他选项会导致调用一个可能高效的函数。 - Omnifarious
我进行了一些分析,并测试了大小不同的向量。在所有情况下,从.data() + v.size()构造或复制是最快的选项。从begin/end迭代器对中构造是最慢的。你列出的第一种方法是第二慢的,但这是因为.resize必须先初始化所有内容。 - Omnifarious

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接