提问人:bers 提问时间:10/26/2023 更新时间:10/26/2023 访问量:102
从字符串文字初始化 char* 向量的好方法是什么?
What is a good way of initializing a vector of char* from string literals?
问:
在 C++11 之前,人们能够编写以下内容:
#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());
}
但是,不再可能将文本值分配给非 - 值。const
char*
幸运的是,从 C++11 开始,我们保证它是以 null 结尾的,因此我们可以执行以下操作:std::string::data()
#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());
}
然而,虽然这有效,但它看起来并不好。有没有更好的方法来初始化非 from 文字的(或数组)?vector
const
char*
答:
在 C++23 中:
std::vector<std::string> strings = {"--foo", "--bar"};
auto ptrs = strings
| std::views::transform([](auto &s){return s.data();})
| std::ranges::to<std::vector>();
Libstdc++ 还没有,但这适用于 libc++ 和 MSVC STL。ranges::to
可悲的是,我们不能直接传递给 ,因为是超载的。&std::string::data
transform
data()
评论
static_cast
std::views::transform(static_cast<char* (std::string::*)() noexcept>(&std::string::data))
假设将来会有什么东西取代当前函数,那么对我来说,它似乎更适合简单地使用 shell 脚本 (linux) 或批处理文件 (windows) – 您可以在其中动态修改参数而无需重新编译 (!) – 并且现在只需使函数成为您的真正函数(所以实际上是一个 XY 问题......main_under_test
main
main_under_test
main
不过,如果您坚持使用当前的方法,那么您可以使用这些指针来初始化数组,而不是创建指向字符串文字的指针:
char raw[][128] = { "--foo", "--bar" };
好了,现在我们有一个二维数组——它不能只是转换为指针数组,所以在这种情况下,我们需要自己在代码中做到这一点,但只需要编写一次:
int main(int argc, char* argv[])
{
char raw[][128] = { "--foo", "--bar" }; // arbitrarily modifiable...
char* args[std::size(raw) + 2] = { *argv }; // the executable name (!)
char** a = args;
for(auto& r : raw)
{
*++a = r;
}
*++a = nullptr; // argv is always null-terminated as well!
return main_under_test(std::size(args) + 1, args);
}
在godbolt上演示。
甚至可以在旧的 C++ 标准上工作(除了必须用 C++ 之前的旧技巧替换11 ...std::size
sizeof
另一种选择是简单地抛弃恒常性(),但随后你依赖于严格承诺不修改参数,否则会产生未定义的行为,因此这种方法不太值得推荐。{ const_cast<char*>("literals") }
main_under_test
评论
main_under_test
main
.obj
main
我认为规范的解决方案是使用:
std::vector<char*> args { const_cast<char*>( "--foo" ),
const_cast<char*>( "--bar" ) }
的主要用途是与旧接口兼容,这些接口不会在应该使用的地方使用。const_cast
const
请注意,如果实际尝试修改 args 中的 s,这将不起作用。如果它是实际的,它很可能不是,但如果有可能,您将不得不以某种方式复制字符串文字,或将它们用作 char[] 的初始值设定项。这可能涉及一个显式循环。main_under_test
char
main
评论
main_under_test
char
main_under_test
评论
std::vector<std::string>
(int, char**)
However, assigning a literal value to a non-const char* is not possible any longer.
– 实际上,无论如何都不应该这样做。C语言的这个遗留功能,现在被放弃了,它是一个漏洞,它引入了用于修改字符串文字的未定义行为。vector<string>
#include <string>