I am trying to wrap my head around variadic templates, move semantics, (maybe perfect forwarding?), and learn how to pass variable down to different functions.
Lets say, there is a class Foo which holds an array of Elem (templated) class instances. These array elements regularly gets re-initialized (hence the Elem.init function).
Below I am trying to initialize an Elem with three large strings (or any other large objects which implements move semantics) to exactly the place where they will be stored: In the Foo's array, at a certain location.
Is that even possible to move them to the Foo's vector location right away? Or will it be always a "copy semantics" instead of a move.
Overall, I am trying to avoid copying large stack allocated strings around and somehow have them be in the target vector's location. Not sure what would be the best way to do that.
(All i got is a segmentation fault at the moment)
Thank you for reading! Code below online: https://onlinegdb.com/HJc7U_jIO
#include <iostream>
#include <vector>
#include <string>
class Elem
{
public:
void init(std::string&& s1, std::string&& s2, std::string&& s3)
{
s1 = std::move(s1);
s2 = std::move(s2);
s3 = std::move(s3);
std::cout << mS1 << mS2 << mS3;
}
private:
std::string mS1;
std::string mS2;
std::string mS3;
};
template <class T>
class Foo
{
public:
template <typename... Args>
void add(Args... args)
{
mElements[mNextFreeIndex].init(args...);
mNextFreeIndex++;
}
private:
std::vector<T> mElements;
int mNextFreeIndex;
};
int main()
{
Foo<Elem> foo;
foo.add(std::move("Apple"), std::move("Pear"), std::move("Carrot")); //passing 3 parameters
return 0;
}
To properly "debug" these issues, you may want to write a class with copy & move constructors, destructor and copy & move assignment operators which declare their being executed. Then you can tell what happens with the values as they get passed around and/or created.
Anyway, you're calling the add()
method with three std::string&&
arguments. But - inside the function, once they are bound to args...
, they are now lvalues! You either need to use std::move()
in your add()
method:
template <typename... Args>
void add(Args... args)
{
mElements[mNextFreeIndex].init(std::move(args)...);
mNextFreeIndex++;
}
or apply forwarding:
template <typename... Args>
void add(Args&&... args)
{
mElements[mNextFreeIndex].init(std::forward<Args>(args)...);
mNextFreeIndex++;
}
On a mostly unrelated note, I would recommend reading this: "Parameter" vs "Argument" regarding the use of these two terms.