如何从字符串字面量正确初始化char*类型的std::vector?
从字面量初始化非const char*类型的vector/数组的最优方式
背景:C++11前后的写法差异
在C++11之前,开发者可以直接用字符串字面量初始化vector<char*>,代码如下:
#include <vector> using namespace std; int main_under_test(int argc, char* argv[]) { return 0; } int main() { vector<char*> args {"--foo", "--bar"}; return main_under_test(args.size(), args.data()); }
但C++11起,字符串字面量的类型是const char[],隐式转换到非const的char*被禁用(避免修改只读内存导致未定义行为),因此上述代码无法再编译通过。
幸运的是,C++11标准保证了std::string::data()返回的指针指向以空字符结尾的内存,因此可以通过std::string中转实现需求,写法如下:
#include <string> #include <vector> using namespace std; int main_under_test(int argc, char* argv[]) { return 0; } int main() { vector<string> strArgs {"--foo", "--bar"}; vector<char*> args; for (auto & strArg : strArgs) { args.push_back(strArg.data()); } return main_under_test(args.size(), args.data()); }
这种写法可行,但代码略显繁琐,下面提供几种更简洁的实现方式:
优化方案
方案1:用std::transform简化循环
可以用标准库的transform算法替代手动循环,让代码更紧凑,同时提前预分配空间提升性能:
#include <string> #include <vector> #include <algorithm> using namespace std; int main_under_test(int argc, char* argv[]) { return 0; } int main() { vector<string> strArgs{"--foo", "--bar"}; vector<char*> args; args.reserve(strArgs.size()); // 预分配空间,避免多次扩容 transform(strArgs.begin(), strArgs.end(), back_inserter(args), [](string& s) { return s.data(); }); return main_under_test(args.size(), args.data()); }
方案2:封装成通用辅助函数
如果需要多次实现类似逻辑,推荐封装一个模板函数,调用时直接传入字面量即可,复用性极强:
#include <string> #include <vector> #include <algorithm> #include <utility> using namespace std; // 辅助函数:将任意数量的字符串字面量/字符串转换为vector<char*> template <typename... Args> vector<char*> make_nonconst_args(Args&&... args) { vector<string> strs{forward<Args>(args)...}; vector<char*> result; result.reserve(strs.size()); transform(strs.begin(), strs.end(), back_inserter(result), [](string& s) { return s.data(); }); return result; } int main_under_test(int argc, char* argv[]) { return 0; } int main() { auto args = make_nonconst_args("--foo", "--bar"); return main_under_test(args.size(), args.data()); }
方案3:手动分配可写内存(适合参数较少的场景)
如果不需要vector的动态特性,也可以直接定义可修改的字符数组,再初始化vector<char*>,这种方式不需要依赖std::string:
#include <vector> using namespace std; int main_under_test(int argc, char* argv[]) { return 0; } int main() { // 定义可写的字符数组,字符串字面量会被复制到栈上的可写内存 char arg1[] = "--foo"; char arg2[] = "--bar"; vector<char*> args{arg1, arg2}; return main_under_test(args.size(), args.data()); }
方案4:用lambda直接初始化vector
可以借助lambda表达式在初始化vector<char*>时完成转换,减少变量声明的行数:
#include <string> #include <vector> using namespace std; int main_under_test(int argc, char* argv[]) { return 0; } int main() { vector<string> strArgs{"--foo", "--bar"}; vector<char*> args{[&]() { vector<char*> tmp; tmp.reserve(strArgs.size()); for (auto& s : strArgs) tmp.push_back(s.data()); return tmp; }()}; return main_under_test(args.size(), args.data()); }
注意事项
- 必须保证
std::string的生命周期长于char*的使用周期,否则会出现悬空指针; - 通过
std::string::data()获取的指针指向可写内存,可以安全修改(前提是不超出字符串的容量); - 方案3中的字符数组存储在栈上,适合短字符串,长字符串建议用
std::string避免栈溢出。
内容的提问来源于stack exchange,提问作者bers
相关产品推荐
相关产品推荐

