【问题标题】:How should I write function parameters to enforce a move rather than a copy?我应该如何编写函数参数来强制移动而不是复制?
【发布时间】:2014-01-08 19:31:00
【问题描述】:

我想使用该类的构造函数将一个大型容器从返回值移动到另一个类。如何制定参数以确保它最终不会被复制?

/* for the sake of simplicity, imagine this typedef to be global */
typedef std::unordered_map<std::string, unsigned int> umap;

umap foo()
{
    umap m; /* fill with lots of data */
    return m;
}

class Bar
{
public:
    Bar(umap m) : bm(m) { }
private:
    umap bm;
};

Bar myBar(foo()); // run foo and pass return value directly to Bar constructor

上述公式会触发适当的行为,还是我需要将构造函数的参数指定为右值引用,就像容器为自己的移动语义所做的那样?

public:
    Bar(umap&& m) : bm(m) { }

public:
    Bar(umap&& m) : bm(std::move(m)) { }

...?

【问题讨论】:

标签: c++ c++11 parameters move-semantics


【解决方案1】:

如果你想支持移动复制,最简单的方法是to pass by value:

Bar(umap m) : bm(std::move(m)) { }

现在您可以从左值和右值构造Bar

umap m;
Bar b1(m);               // copies
Bar b2(std::move(m));    // moves
Bar b3(make_umap());     // moves

如果您想要支持右值,那么使用显式的右值引用:

Bar(umap && m) : bm(std::move(m)) { }

std::move 始终是必需的,因为 (m) 始终是左值。

【讨论】:

    【解决方案2】:

    强制将右值传递给构造函数,并确保移动地图,如下所示:

    Bar(umap &&m) : bm(std::move(m)) {}
    

    从第一个例子开始,到上面的解决方案:

    让我们从Bar(umap m) : bm(m) {} 的第一个示例开始。这将执行至少 1 个副本,也许 2 个。

    bm(m) 将始终复制。 m 这里是左值,即使它绑定右值。要使其移动,您必须将其包装在 std::move 中以将其转回 rvalue。我们得到bm(std::move(m))

    Bar(umap m) 可能会复制。如果它是 rvalue,则该值将被移入,但如果它是 lvalue,则将被复制。由于我们要阻止所有副本,我们只需要让 rvalue 绑定。我们得到Bar(umap &amp;&amp; m)

    【讨论】:

      【解决方案3】:

      除了上面的答案:

      我在您的示例中看到的是“复制省略”优化的经典案例。

      What are copy elision and return value optimization?

      一个实际的编译器不需要你的支持来优化这些东西,在这种返回值优化的特殊情况下,也没有必要自己处理右值引用。

      【讨论】:

        【解决方案4】:

        在 C++11 中,您使用 std::move。如果你需要 C++03 兼容性,你可以 default-construct bm via :bm() 然后使用 using std::swap; swap(bm, m);

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-08-13
          • 1970-01-01
          • 1970-01-01
          • 2013-01-29
          • 1970-01-01
          • 1970-01-01
          • 2015-12-30
          • 2021-03-12
          相关资源
          最近更新 更多