【问题标题】:Using variadic templates and move semantics使用可变参数模板和移动语义
【发布时间】:2021-04-19 21:31:07
【问题描述】:

我正试图围绕可变参数模板进行思考, 移动语义,(也许是完美的转发?), 并学习如何将变量传递给不同的函数。

比方说,有一个类 Foo 包含一个 Elem(模板化)类实例的数组。 这些数组元素会定期重新初始化(因此是 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;
}

【问题讨论】:

    标签: c++11 variadic-templates move-semantics


    【解决方案1】:

    要正确“调试”这些问题,您可能需要编写一个具有复制和移动构造函数、析构函数和复制和移动赋值运算符的类,这些运算符声明它们正在执行。然后,您可以了解这些值在传递和/或创建时会发生什么。

    无论如何,您正在使用三个 std::string&amp;&amp; 参数调用 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"

    【讨论】:

    • 还有一个问题:所以要么我在任何地方都使用std::move,要么要么std::forward,所以我应该混合它们吗?
    • @Avi:这里没有我可以给你的一般规则。转发适用于需要相同代码同时处理右值和左值引用的情况。而且 - 如果你发现自己经常移动或转发很多,那么 - 也许你应该简单地争取更少的代码层。
    猜你喜欢
    • 1970-01-01
    • 2018-02-26
    • 2021-10-01
    • 2016-12-01
    • 2016-09-02
    • 1970-01-01
    • 1970-01-01
    • 2018-02-15
    • 2012-11-05
    相关资源
    最近更新 更多