使用可变参数模板和移动语义
Using variadic templates and move semantics
我正在努力思考可变参数模板,
移动语义,(也许是完美的转发?),
并学习如何将变量传递给不同的函数。
比方说,有一个 class Foo 包含一个 Elem(模板化)class 实例数组。
这些数组元素会定期重新初始化(因此 Elem.init 函数)。
下面我尝试用三个大字符串(或任何其他实现移动语义的大对象)将 Elem 初始化到它们将被存储的确切位置:
在 Foo 的数组中,在某个位置。
是否可以立即将它们移动到 Foo 的矢量位置?
或者它会永远是“复制语义”而不是移动。
总的来说,我试图避免复制大堆栈分配的字符串,并以某种方式让它们位于目标向量的位置。
不确定最好的方法是什么。
(我目前得到的只是一个分段错误)
感谢阅读!
在线代码如下: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;
}
为了正确地“调试”这些问题,您可能需要编写一个 class,其中包含声明正在执行的复制和移动构造函数、析构函数以及复制和移动赋值运算符。然后你可以知道当这些值在 and/or created.
周围传递时会发生什么
无论如何,您正在使用三个 std::string&&
参数调用 add()
方法。但是 - 在函数内部,一旦它们绑定到 args...
,它们现在就是 lvalues!您要么需要在 add()
方法中使用 std::move()
:
template <typename... Args>
void add(Args... args)
{
mElements[mNextFreeIndex].init(std::move(args)...);
mNextFreeIndex++;
}
或应用转发:
template <typename... Args>
void add(Args&&... args)
{
mElements[mNextFreeIndex].init(std::forward<Args>(args)...);
mNextFreeIndex++;
}
关于一个几乎不相关的说明,我建议阅读以下内容:"Parameter" vs "Argument" 关于这两个术语的使用。
我正在努力思考可变参数模板, 移动语义,(也许是完美的转发?), 并学习如何将变量传递给不同的函数。
比方说,有一个 class Foo 包含一个 Elem(模板化)class 实例数组。 这些数组元素会定期重新初始化(因此 Elem.init 函数)。
下面我尝试用三个大字符串(或任何其他实现移动语义的大对象)将 Elem 初始化到它们将被存储的确切位置: 在 Foo 的数组中,在某个位置。
是否可以立即将它们移动到 Foo 的矢量位置? 或者它会永远是“复制语义”而不是移动。
总的来说,我试图避免复制大堆栈分配的字符串,并以某种方式让它们位于目标向量的位置。 不确定最好的方法是什么。
(我目前得到的只是一个分段错误)
感谢阅读! 在线代码如下: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;
}
为了正确地“调试”这些问题,您可能需要编写一个 class,其中包含声明正在执行的复制和移动构造函数、析构函数以及复制和移动赋值运算符。然后你可以知道当这些值在 and/or created.
周围传递时会发生什么无论如何,您正在使用三个 std::string&&
参数调用 add()
方法。但是 - 在函数内部,一旦它们绑定到 args...
,它们现在就是 lvalues!您要么需要在 add()
方法中使用 std::move()
:
template <typename... Args>
void add(Args... args)
{
mElements[mNextFreeIndex].init(std::move(args)...);
mNextFreeIndex++;
}
或应用转发:
template <typename... Args>
void add(Args&&... args)
{
mElements[mNextFreeIndex].init(std::forward<Args>(args)...);
mNextFreeIndex++;
}
关于一个几乎不相关的说明,我建议阅读以下内容:"Parameter" vs "Argument" 关于这两个术语的使用。