RAII char ** to be used as exec argument vector - c++

I'm currently creating an app to launch external apps.
The signature to launch the external apps is:
int launchApp(int argc, char** argv); // argc = amount of arguments, argv = arguments
To add arguments to a std::vector<char *> structure I use the following 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()] = '\0';
lArguments.push_back(cstr);
};
And launching an external app:
std::vector<char *> lArguments;
addArgument(lArguments, "Argument 1");
addArgument(lArguments, "Argument 2");
launchApp(lArguments.size(),static_cast<char**>(lArguments.data());
//... Clean up arguments
How would I do this in a RAII manner instead?
I was thinking of using a std::vector<std::vector<char>> instead. However, how can I then pass the underlying raw data (char**) to launchApp()? static_cast<char**>(lArguments.data()) wouldn't work...

I usually do this in two parts:
Build a std::vector<std::string> containing the actual arguments.
Build a std::vector<const char*> where each element is the .data() of the corresponding element in the vector of strings.
The first vector, and the strings contained within it, handle your allocation, resizing, etc. while the second simply acts as an index into the memory that is being managed by the first. The lifetime of your second vector should be shorter than that of the first, which you can guarantee by wrapping both in a class.
Example:
#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()));
}
(Note the ugly const_cast. Depending on how you look at it, this is either because the exec* family of functions don't follow const correctness, or because std::string::data() does not have a non-const version (prior to C++17)).
Or, 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());
}

Collect your parameters as regular strings.
Use an inner class that:
provides a transparent implicit view to a raw array of pointers, and
takes care of managing this pointer array at the same time.
An instance of this inner class is returned by some access method. Its lifetime spans the invoking statement. See below for an example:
#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());
}

Related

How to create a class that stores pointers to member functions (C++)

I'm trying to create a class that stores pointers to member functions of other classes and that can be executed from a text command (like a game console).
I did something functional, based on an example found here, that stores members with string-like input. Below is my implementation.
file: Command.hpp
#include <string>
#include <functional>
#include <unordered_map>
#include <string>
#include <iostream>
using namespace std;
class Command
{
public:
Command();
virtual ~Command();
void RegisterCommand(string command, function<void(const string&)> fun);
void Run(const string& command, const string& arg);
private:
unordered_map<string, function<void(const string&)>> functions;
};
file: Command.cpp
Command::Command()
{
}
Command::~Command()
{
}
void Command::RegisterCommand(string command, function<void(const string&)> fun)
{
functions[command] = fun;
}
void Command::Run(const string& command, const string& arg)
{
functions[command](arg);
}
file: main.cpp
#include "Command.hpp"
// function to register
void xyz_fun(const string& commandLine)
{
cout << "console output: " << commandLine << endl;
}
int main(int argc, char* argv[])
{
Command m_Cmd;
// Register function
m_Cmd.RegisterCommand("xyz_fun", xyz_fun);
// Run registered function
m_Cmd.Run("xyz_fun", "hello world.");
return EXIT_SUCCESS;
}
My question is how to implement a generic class to store members with unknown input arguments (Booleans, integers, doubles, strings, etc.).
For example, I could do:
m_Cmd.RegisterCommand("xyz_fun2", xyz_function2);
and call
m_Cmd.Run("xyz_fun2", false)
which has a boolean argument instead of a string.
Thanks in advance for your attention and any help is welcome.
Instead of
unordered_map<string, function<void(const string&)>> functions;
you could do
union acceptable_types { int i; char c; bool b; std::string* s; ... };
unordered_map<string, function<void(acceptable_types)>> functions;
Then when calling functions, just place the value wanted by the function into a variable of type acceptable_types.
If a function is wants to use a specific value, it should just use a specific member of the acceptable_types union.
Here's an example:
#include "Command.hpp"
void
my_bool_func (acceptable_types union_param)
{
bool bool_var = union_param.b;
// ...
// Use bool_var
// ...
}
void
my_string_func (acceptable_types union_param)
{
std::string string_var = *(union_param.s);
// ...
// Use string_var
// ...
}
int
main(int argc, char* argv[])
{
Command my_command;
acceptable_types union_var;
my_command.RegisterCommand("my_bool_func", my_bool_func);
my_command.RegisterCommand("my_string_func", my_string_func);
union_var.b = true;
my_command.Run("my_bool_func", union_var);
*(union_var.s) = "hello world.";
my_command.Run("my_string_func", union_var);
return 0;
}

C++ Passing a class method as function pointer

I have a class that has to process data from various files. I thought about creating one function that will read the specified file and then also accept a call back so that it can use that to process the line. Below is an example class to represent what I am trying to do:
#include <iostream>
#include <vector>
#include <string>
class Example
{
std::vector<std::string> m_exampleFileData {
"test1",
"test2",
"test3"
};
public:
void doSomethingMain(const std::string& path)
{
processFile(path, doSomething);
}
private:
void processFile(const std::string& filePath, void (Example::*fpProcessLine)(const std::string&) )
{
for (const auto& line : m_exampleFileData) {
this->*fpProcessLine(line);
}
}
void doSomething(const std::string& line)
{
std::cout << "Hello: " << line << '\n';
}
};
int main(int argc, char** argv) {
const std::string filePath{"path"};
Example ex;
ex.doSomethingMain(filePath);
}
Compiler explorer: https://godbolt.org/z/LKoXSZ
The main issue is that no matter what I do I can't seem to be able to pass the function properly to processFile. Is there a way to do this in C++? How do I go about this?
You need to spell things out explicitly, in this situation:
processFile(path, &Example::doSomething);
Furthermore, you also need to slap on an extra pair of parenthesis, due to operator precedence:
(this->*fpProcessLine)(line);

How to copy elements from std::list to an array of struct?

I need to copy the contents of a std::list into an array, wherein the array is struct of array. Below is the code implementation of it.
#include <iostream>
#include <string>
using namespace std;
typedef struct
{
int height;
int width;
int length;
}dimensions;
GetDimensions(list<std::string>, *int); // Function that copies the content of list to array passed as second parameter
int main()
{
dimensions cuboid[10];
int plane[10];
list<std::string> planeList = GetList();//Function that returns list of elements
list<std::string> dimensionList = GetList();
GetDimensions(planeList,&plane);//This is fine, as it is a simple array
GetDimensions(dimensionList,&cuboid.height);//Trouble in implementation of this usecase, for cuboid.height, cuboid.width and cuboid.height.
return 0;
}
GetDimensions(list<std::string>dimensionList, int* dimensionParams)
{
int i=0;
for(list<std::string>::iterator it = dimensionList.begin(); it != dimensionList.end(); ++it)
{
dimensionParams[i] = stoi(*it);
i++;
}
}
Here, I need GetDimensions() function to copy the list (passed as first parameter) to array (second parameter). The implemented function works well for simple array plane. But how to pass the array of struct as parameter to the function ?
I will be getting the std::list as cuboid.height, cuboid.width and cuboid.length. So the function has to copy the contents of list from cuboid[0].height to cuboid[i].height respectively. Is there any specific function to copy the content directly?
Use std::array 's instead. Then your problem can be reduced to passing two different types of arrays to a single function.
This can be solved
either by good old function overloads
or in c++17 function template with
if-constexpr.
Following is an example code with templated function with if-constexpr (See live online)
#include <iostream>
#include <string>
#include <list>
#include <array>
#include <type_traits> // std::is_same_v
struct dimensions // no need to typedef here
{
int height;
int width;
int length;
};
template<typename T>
void GetDimensions(const list<std::string>& dimensionList, T& dimensionParams)
^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //---> pass list by const-ref as the values are non-modifying
{
int i{0};
if constexpr (std::is_same_v<std::array<int, 10>, T>)
{
for(const std::string& str: dimensionList) dimensionParams[i++] = std::stoi(str);
}
else
{
for(const std::string& str: dimensionList) dimensionParams[i++].height = std::stoi(str);
}
}
int main()
{
std::array<dimensions, 10> cuboid; // use std::array instead of VLA
std::array<int, 10> plane;
std::list<std::string> planeList{"1", "2"}; // some list
std::list<std::string> dimensionList{"1", "2"};
GetDimensions(planeList, plane);
GetDimensions(dimensionList, cuboid);
return 0;
}
Also note that:
You have not specified the return type of GetDimensions function.
You probably want to return void there.
in C++ you do not need to use typedef alias for struct { ... }.
last but not least, do not practice with using namespace std;
You can do this with boost::transform_iterator.
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <boost/iterator/transform_iterator.hpp>
struct dimensions {
int height;
int width;
int length;
};
template <typename OutputIt>
void GetDimensions(std::list<std::string> dimensionList, OutputIt dimensionParams)
{
// N.b. taking the address of a standard library function is undefined, so wrap in a lambda
auto stoi = [](std::string s){ return std::stoi(s); };
std::copy(boost::make_transform_iterator(dimensionList.begin(), stoi),
boost::make_transform_iterator(dimensionList.end(), stoi),
dimensionParams);
}
int main() {
dimensions cuboid[10];
int plane[10];
std::list<std::string> planeList = GetList();
std::list<std::string> heightList = GetList();
std::list<std::string> widthList = GetList();
std::list<std::string> lengthList = GetList();
GetDimensions(planeList, plane);
GetDimensions(heightList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::height)));
GetDimensions(widthList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::width)));
GetDimensions(lengthList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::length)));
return 0;
}

C++ class and method that search values in map

I have written a minimum class to better submit my problem.
I have three files:
1) test.hpp
#include <cstdlib>
#include <stdio.h>
#include <map>
class test {
public:
test () {}
~test () {}
const char *getPin (const char *);
private:
static const std::map<const char *, const char *> pinIndex;
static std::map<const char *, const char *> initializePins ();
};
2) test.cpp
#include "test.hpp"
const std::map<const char *, const char *> test::pinIndex = test::initializePins ();
std::map<const char *, const char *> test::initializePins () {
std::map<const char *, const char *> pins;
pins.insert (
std::pair<const char *, const char *> (
"AAAA", "BBBB"
)
);
return pins;
}
const char *test::getPin (const char *pinNumber) {
if (pinIndex.count (pinNumber) > 0) {
return pinIndex.at (pinNumber);
}
else {
printf ("Undefined pin %s!\n", pinNumber);
exit (EXIT_FAILURE);
}
}
3) main.cpp
#include "test.hpp"
int main () {
test myExample;
const char *a = myExample.getPin ("AAAA");
exit (EXIT_SUCCESS);
}
When I compile and run it I get this error:
Undefined pin AAAA!
If I remove main.cpp and put the main function in test.cpp file, I do not get me any error and GetPin returns the correct value.
Any idea what I'm doing wrong?
Thank you
Your problem is that you're using char* pointers in your map as key values. To find entries in the map, the implementation uses comparison operations (<) for the given key.
If you're going to compare char* pointers those will almost never be the same, and are completely unrelated to their contents, which is what you're actually want to look for.
A simple solution for your problem would be to change your map type to
std::map<std::string, std::string>
Another possible solution is to provide a class that compares two char* pointers based on content as the 3rd template parameter of the map
std::map<char*, char*, MyComparer>
where MyComparer is s.th. like this
struct MyComparer {
bool operator()( const char*& lhs, const char*& rhs ) const {
return strcmp(lhs,rhs) < 0;
}
};
As an explanation why you experience that seemingly inconsistent behavior, when moving your test to a separate compilation unit:
If you have the same string literals (e.g. "AAAA") appearing in the TU multiple times, the compiler can optimize them to be stored just once, and thus you'll have the same address for all of their appearances.
There is no guarantee that "AAAA" will have the same address as "AAAA" used somewhere else in your program. So finding "AAAA" is not guaranteed to work since the map will be comparing pointer values.
Use a std::map<std::string, std::string> instead of std::map<const char *, const char *>, and your issue should be resolved.
Your solution is quite simple:
#include <iostream>
#include <map>
#include <string>
int
main ()
{
std::map<std::string, std::string> pins { { "AAAA" , "BBBB" }, { "CCCC" , "DDDD" } };
auto lookup = pins.find("AAAA");
if (lookup != pins.end())
std::cout << "Pin AAAA found!" << std::endl;
else
std::cerr << "Pin AAAA not found!" << std::endl;
return 0;
}
A couple of suggestions:
Never use c-strings in C++ code. That is not faster but much more heavy to process. The std::string always knows ones length and performs better in comparisons.
Write as few as you can since KISS (keep it simple stupid) in 90% is the best idea.

Variadic function without specified first parameter?

Out of curiosity, I thought I'd try and write a basic C++ class that mimics C#'s multiple delegate pattern. The code below mostly does the job, with the nasty sacrifice of losing almost all type-safety, but having to use the initial dummy parameter to set up the va_list really seems a bit off. Is there a way to use va_list without this?
I do realize there are ways to do this with (for example) boost, but I was aiming for something dead simple that used just the standard library.
#include <vector>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <algorithm>
using namespace std;
class CDelegate
{
public:
virtual bool operator()(va_list params) = 0;
};
class CMultipleDelegateCaller
{
public:
typedef vector<CDelegate*> CDelegateVector;
CMultipleDelegateCaller& operator+=(CDelegate &rDelegate)
{
m_apDelegates.push_back(&rDelegate);
return (*this);
}
CMultipleDelegateCaller& operator-=(CDelegate &rDelegate)
{
CDelegateVector::iterator iter =
find(m_apDelegates.begin(), m_apDelegates.end(), &rDelegate);
if (m_apDelegates.end() != iter) m_apDelegates.erase(iter);
return (*this);
}
bool Call(int iDummy, ...)
{
va_list params;
CDelegate* pDelegate;
CDelegateVector::iterator iter;
for (iter = m_apDelegates.begin(); iter != m_apDelegates.end(); ++iter)
{
pDelegate = *iter;
va_start(params, iDummy);
if (!(*pDelegate)(params)) return false;
va_end(params);
}
return true;
}
private:
CDelegateVector m_apDelegates;
};
class CTestDelegate:
public CDelegate
{
public:
CTestDelegate():m_iId(++s_iCount) {}
virtual bool operator()(va_list params)
{
int iIntParam = va_arg(params, int);
char* szCharPtrParam = va_arg(params, char*);
string* psStringParam = va_arg(params, string*);
cout<<m_iId<<"{"
<<iIntParam<<", "
<<szCharPtrParam<<", "
<<*psStringParam<<"}"<<endl;
return true;
}
int m_iId;
static int s_iCount;
};
int CTestDelegate::s_iCount = 0;
int main(int argc, char* argv[])
{
CMultipleDelegateCaller cDelegateCaller;
CTestDelegate cTestDelegate1;
CTestDelegate cTestDelegate2;
cout<<"--------------------"<<endl;
cDelegateCaller += cTestDelegate1;
cDelegateCaller += cTestDelegate2;
string sString("World");
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cDelegateCaller -= cTestDelegate1;
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cDelegateCaller -= cTestDelegate2;
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cin>>sString;
return 0;
}
Functions with ellipsis in C++ is only for compatibility with C. Using C++ I'd return temporary helper object in Call function and add template operator% to pass variable number of arguments. To use it in the following way:
cDelegateCaller.Call() % 2 % "Hello" % sString; // dummy argument isn't required
As to your question, Standard requires to invoke va_start before any access to the unnamed arguments. And va_start requires second argument which is the identifier of the rightmost parameter in the variable parameter list in the function definition.
Out of Kirill's answer you can conclude that it's possible to create a type-safe delegate, using a template argument-combining function. This function also needs a dummy starting point, but has the benefit of type-safety.
The FastFormat library uses this, boost uses this, and I once provided another example in an answer to another question.