RAII char ** 用作 exec 参数向量
RAII char ** to be used as exec argument vector
我目前正在创建一个应用程序来启动外部应用程序。
启动外部应用程序的签名是:
int launchApp(int argc, char** argv); // argc = amount of arguments, argv = arguments
要向 std::vector<char *>
结构添加参数,我使用以下 lambda:
auto addArgument = [](std::vector<char *> & lArguments,
const std::string & sArgument)
{
auto cstr = new char[sArgument.size() + 1];
std::copy(sArgument.cbegin(), sArgument.cend(), cstr);
cstr[sArgument.size()] = '[=11=]';
lArguments.push_back(cstr);
};
并启动外部应用程序:
std::vector<char *> lArguments;
addArgument(lArguments, "Argument 1");
addArgument(lArguments, "Argument 2");
launchApp(lArguments.size(),static_cast<char**>(lArguments.data());
//... Clean up arguments
我如何以 RAII 方式执行此操作?
我正在考虑改用 std::vector<std::vector<char>>
。但是,我怎样才能将底层原始数据 (char**
) 传递给 launchApp()
? static_cast<char**>(lArguments.data())
不行...
我通常分两部分进行:
- 构建一个包含实际参数的
std::vector<std::string>
。
- 构建一个
std::vector<const char*>
,其中每个元素都是字符串向量中相应元素的 .data()
。
第一个向量及其中包含的字符串处理您的分配、调整大小等,而第二个向量仅充当第一个管理的内存的索引。你的第二个向量的生命周期应该比第一个短,你可以通过将两者都包装在 class.
中来保证这一点
#include <string>
#include <vector>
#include <unistd.h>
int main() {
std::vector<std::string> args = {"echo", "hello", "world"};
std::vector<const char*> argv;
argv.reserve(args.size());
for (auto& arg : args) {
argv.push_back(arg.data());
}
execvp("echo", const_cast<char**>(argv.data()));
}
(注意丑陋的 const_cast
。这取决于你如何看待它,这要么是因为 exec*
family of functions don't follow const correctness, or because std::string::data()
没有非常量版本(C++17 之前)) .
或者,with the class to wrap it all up nicely:
#include <string>
#include <vector>
#include <unistd.h>
class ExecArguments {
public:
ExecArguments(std::initializer_list<std::string> arguments)
: args(arguments) {
for (auto& arg : args) {
argv.push_back(const_cast<char*>(arg.data()));
}
}
char** data() {
return const_cast<char**>(argv.data());
}
private:
std::vector<std::string> args;
std::vector<char*> argv;
};
int main() {
ExecArguments args{"echo", "hello", "world"};
execvp(args.data()[0], args.data());
}
- 将您的参数收集为常规字符串。
- 使用内部 class :
- 为原始指针数组提供透明的隐式视图,并且
- 同时负责管理这个指针数组。
此内部 class 的实例由某种访问方法返回。它的生命周期跨越调用语句。请参阅下面的示例:
#include <iostream>
#include <vector>
class CollectArgs : public std::vector<std::string> {
// just for providing the raw view and taking care of its memory
class RawArgs {
std::vector<char const*> m_argv;
public:
RawArgs(std::vector<char const*> argv) {
std::swap(argv, m_argv);
}
~RawArgs() {}
public:
operator char const* const*() const { return m_argv.data(); }
};
public:
RawArgs raw_args() const {
std::vector<char const*> argv;
for(std::string const &arg : *this) argv.push_back(arg.c_str());
return argv;
}
};
// the application launcher
void call(unsigned argc, char const *const *argv) {
for(unsigned i = 0; i < argc; i++) {
std::cout << argv[i] << std::endl;
}
}
int main() {
CollectArgs args;
args.push_back("Arg1");
args.push_back("Arg2");
// create the raw view and have it destroyed immediately after this statement
call(args.size(), args.raw_args());
}
我目前正在创建一个应用程序来启动外部应用程序。 启动外部应用程序的签名是:
int launchApp(int argc, char** argv); // argc = amount of arguments, argv = arguments
要向 std::vector<char *>
结构添加参数,我使用以下 lambda:
auto addArgument = [](std::vector<char *> & lArguments,
const std::string & sArgument)
{
auto cstr = new char[sArgument.size() + 1];
std::copy(sArgument.cbegin(), sArgument.cend(), cstr);
cstr[sArgument.size()] = '[=11=]';
lArguments.push_back(cstr);
};
并启动外部应用程序:
std::vector<char *> lArguments;
addArgument(lArguments, "Argument 1");
addArgument(lArguments, "Argument 2");
launchApp(lArguments.size(),static_cast<char**>(lArguments.data());
//... Clean up arguments
我如何以 RAII 方式执行此操作?
我正在考虑改用 std::vector<std::vector<char>>
。但是,我怎样才能将底层原始数据 (char**
) 传递给 launchApp()
? static_cast<char**>(lArguments.data())
不行...
我通常分两部分进行:
- 构建一个包含实际参数的
std::vector<std::string>
。 - 构建一个
std::vector<const char*>
,其中每个元素都是字符串向量中相应元素的.data()
。
第一个向量及其中包含的字符串处理您的分配、调整大小等,而第二个向量仅充当第一个管理的内存的索引。你的第二个向量的生命周期应该比第一个短,你可以通过将两者都包装在 class.
中来保证这一点#include <string>
#include <vector>
#include <unistd.h>
int main() {
std::vector<std::string> args = {"echo", "hello", "world"};
std::vector<const char*> argv;
argv.reserve(args.size());
for (auto& arg : args) {
argv.push_back(arg.data());
}
execvp("echo", const_cast<char**>(argv.data()));
}
(注意丑陋的 const_cast
。这取决于你如何看待它,这要么是因为 exec*
family of functions don't follow const correctness, or because std::string::data()
没有非常量版本(C++17 之前)) .
或者,with the class to wrap it all up nicely:
#include <string>
#include <vector>
#include <unistd.h>
class ExecArguments {
public:
ExecArguments(std::initializer_list<std::string> arguments)
: args(arguments) {
for (auto& arg : args) {
argv.push_back(const_cast<char*>(arg.data()));
}
}
char** data() {
return const_cast<char**>(argv.data());
}
private:
std::vector<std::string> args;
std::vector<char*> argv;
};
int main() {
ExecArguments args{"echo", "hello", "world"};
execvp(args.data()[0], args.data());
}
- 将您的参数收集为常规字符串。
- 使用内部 class :
- 为原始指针数组提供透明的隐式视图,并且
- 同时负责管理这个指针数组。
此内部 class 的实例由某种访问方法返回。它的生命周期跨越调用语句。请参阅下面的示例:
#include <iostream>
#include <vector>
class CollectArgs : public std::vector<std::string> {
// just for providing the raw view and taking care of its memory
class RawArgs {
std::vector<char const*> m_argv;
public:
RawArgs(std::vector<char const*> argv) {
std::swap(argv, m_argv);
}
~RawArgs() {}
public:
operator char const* const*() const { return m_argv.data(); }
};
public:
RawArgs raw_args() const {
std::vector<char const*> argv;
for(std::string const &arg : *this) argv.push_back(arg.c_str());
return argv;
}
};
// the application launcher
void call(unsigned argc, char const *const *argv) {
for(unsigned i = 0; i < argc; i++) {
std::cout << argv[i] << std::endl;
}
}
int main() {
CollectArgs args;
args.push_back("Arg1");
args.push_back("Arg2");
// create the raw view and have it destroyed immediately after this statement
call(args.size(), args.raw_args());
}