使用可变参数模板和移动语义

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" 关于这两个术语的使用。