标签: move-semantics

我可以/通常使用std :: forward而不是std :: move吗?

我一直在观看Scott Meyers 关于 C++和2012 年之后的Universal References演讲,到目前为止一切都很有意义.然而,一位观众在大约50分钟后问了一个问题,我也在想.迈尔斯说,他不关心答案,因为它不是惯用的,会愚蠢的想法,但我仍然感兴趣.

提供的代码如下:

// Typical function bodies with overloading:
void doWork(const Widget& param)   // copy
{
  // ops and exprs using param
}
void doWork(Widget&& param)        // move
{
  // ops and exprs using std::move(param)
}

// Typical function implementations with universal reference:
template <typename T>
void doWork(T&& param)             // forward => copy and move
{
  // ops and exprs using std::forward<T>(param)
}
Run Code Online (Sandbox Code Playgroud)

关键是当我们采用右值引用时,我们知道我们有一个右值,所以我们应该std::move保留它是一个右值的事实.当我们采用通用引用(T&&其中T是推导类型)时,我们希望std::forward保留它可能是左值或右值的事实.

所以问题是:既然 …

c++ rvalue-reference move-semantics perfect-forwarding c++11

63
推荐指数
2
解决办法
7217
查看次数

是否应将C++ 11中的所有/大多数setter函数编写为接受通用引用的函数模板?

考虑一个X具有N成员变量的类,每个类都有一些可复制可移动的类型,以及N相应的setter函数.在C++ 98中,定义X可能如下所示:

class X
{
public:
    void set_a(A const& a) { _a = a; }
    void set_b(B const& b) { _b = b; }
    ...
private:
    A _a;
    B _b;
    ...
};
Run Code Online (Sandbox Code Playgroud)

X上面类的setter函数可以绑定到左值和右值参数.根据实际的说法,这可能导致创建临时的,并最终导致的分配副本; 因此,此设计不支持不可复制的类型.

使用C++ 11,我们可以移动语义,完美转发和通用引用(Scott Meyers的术语),通过以下方式重写它们,可以更有效和广泛地使用setter函数:

class X
{
public:
    template<typename T>
    void set_a(T&& a) { _a = std::forward<T>(a); }

    template<typename T>
    void set_b(T&& b) { _b = std::forward<T>(b); } …
Run Code Online (Sandbox Code Playgroud)

c++ move-semantics perfect-forwarding c++11 universal-reference

63
推荐指数
1
解决办法
4808
查看次数

为什么在C++ 11中使用&&时使用std :: move?

可能重复:
有人可以向我解释移动语义吗?

我最近参加了一个C++ 11研讨会,并给出了以下一些建议.

when you have && and you are unsure, you will almost always use std::move
Run Code Online (Sandbox Code Playgroud)

任何人都可以向我解释为什么你应该使用std::move而不是某些替代品以及某些不应该使用的情况std::move

c++ move-semantics c++11

59
推荐指数
2
解决办法
3万
查看次数

为什么派生类在基类不可移动时可以构造?

请考虑以下示例:

#include <iostream>
#include <string>
#include <utility>

template <typename Base> struct Foo : public Base {
    using Base::Base;
};

struct Bar {
    Bar(const Bar&) { }
    Bar(Bar&&) = delete;
};

int main() {
    std::cout << std::is_move_constructible<Bar>::value << std::endl; // NO
    std::cout << std::is_move_constructible<Foo<Bar>>::value << std::endl; // YES. Why?!
}
Run Code Online (Sandbox Code Playgroud)

尽管基类是不可移动构造的,为什么编译器会生成移动构造函数?

这是标准还是编译器错误?是否有可能"完美地传播"将构造从基础移动到派生类?

c++ language-lawyer move-constructor move-semantics c++11

57
推荐指数
2
解决办法
2049
查看次数

为什么有些人使用交换进行移动分配?

例如,stdlibc ++具有以下内容:

unique_lock& operator=(unique_lock&& __u)
{
    if(_M_owns)
        unlock();
    unique_lock(std::move(__u)).swap(*this);
    __u._M_device = 0;
    __u._M_owns = false;
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

为什么不直接将两个__成员分配给*?交换是否意味着__u被分配了*this成员,后来才分配0和false ...在这种情况下交换正在做不必要的工作.我错过了什么?(unique_lock :: swap只对每个成员执行std :: swap)

c++ rvalue-reference move-semantics copy-and-swap c++11

56
推荐指数
2
解决办法
2万
查看次数

为什么std :: move会阻止RVO?

在许多情况下,从函数返回局部时,RVO会启动.但是,我认为显式使用std::move至少会在RVO未发生时执行移动,但RVO仍然会在可能的情况下应用.但是,似乎情况并非如此.

#include "iostream"

class HeavyWeight
{
public:
    HeavyWeight()
    {
        std::cout << "ctor" << std::endl;
    }

    HeavyWeight(const HeavyWeight& other)
    {
        std::cout << "copy" << std::endl;
    }

    HeavyWeight(HeavyWeight&& other)
    {
        std::cout << "move" << std::endl;
    }
};

HeavyWeight MakeHeavy()
{
    HeavyWeight heavy;
    return heavy;
}

int main()
{
    auto heavy = MakeHeavy();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我用VC++ 11和GCC 4.71,debug和release(-O2)配置测试了这段代码.永远不会调用复制文件.移动ctor仅在调试配置中由VC++ 11调用.实际上,特别是这些编译器似乎都很好,但据我所知,RVO是可选的.

但是,如果我明确使用move:

HeavyWeight MakeHeavy()
{
    HeavyWeight heavy;
    return std::move(heavy);
}
Run Code Online (Sandbox Code Playgroud)

移动ctor总是被称为.因此,试图使其"安全"会使情况变得更糟.

我的问题是:
- 为什么要std::move预防RVO?
- 何时更好地"希望最好"并依赖RVO,何时应该明确使用 …

c++ move-semantics rvo c++11

51
推荐指数
2
解决办法
1万
查看次数

std :: function的仅移动版本

因为std::function是可复制的,所以标准要求用于构造它的callables也是可复制的:

n337(20.8.11.2.1)

template<class F> function(F f);

要求:F应为CopyConstructible.f对于参数类型ArgTypes和返回类型,应为Callable(20.8.11.2)R.A的拷贝构造函数和析构函数不会抛出异常

这意味着不可能std::function从不可复制的绑定对象或捕获仅移动类型的lambda形成std::unique_ptr.

似乎可以为仅移动的callables实现这样一个仅移动的包装器.是否存在标准库仅限移动等效std::function或者,是否存在针对此问题的常见解决方法?

c++ move-semantics c++11

51
推荐指数
3
解决办法
6242
查看次数

引用超载,与单值传递+ std :: move相比?

看来关于C++ 0x的rvalues的主要建议是添加移动构造函数并将运算符移动到类中,直到编译器默认实现它们.

但是如果使用VC10,等待是一种失败的策略,因为自动生成可能不会在VC10 SP1之前,或者在最坏的情况下,VC11.可能,等待这个将是多年来衡量.

这就是我的问题.编写所有这些重复的代码并不好玩.这看起来很不愉快.但对于那些认为很慢的课程来说,这是一个很受欢迎的负担.对于数百个(如果不是数千个)较小的类而言,情况并非如此.

::叹气:: C++ 0x应该让我写更少的代码,而不是更多!

然后我有了一个想法.很多人都愿意共享,我猜.

为什么不按价值传递一切?不会std :: move + copy elision使这几乎达到最佳状态吗?

示例1 - 典型的Pre-0x构造函数

OurClass::OurClass(const SomeClass& obj) : obj(obj) {}

SomeClass o;
OurClass(o);            // single copy
OurClass(std::move(o)); // single copy
OurClass(SomeClass());  // single copy
Run Code Online (Sandbox Code Playgroud)

缺点: rvalues的浪费副本.

例2 - 推荐的C++ 0x?

OurClass::OurClass(const SomeClass& obj) : obj(obj) {}
OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}

SomeClass o;
OurClass(o);            // single copy
OurClass(std::move(o)); // zero copies, one move
OurClass(SomeClass());  // zero copies, one move
Run Code Online (Sandbox Code Playgroud)

优点:大概是最快的.
缺点:很多代码!

示例3 …

c++ rvalue-reference move-semantics c++11

49
推荐指数
1
解决办法
2960
查看次数

移动语义和功能顺序评估

假设我有以下内容:

#include <memory>
struct A { int x; };

class B {
  B(int x, std::unique_ptr<A> a);
};

class C : public B {
  C(std::unique_ptr<A> a) : B(a->x, std::move(a)) {}
};
Run Code Online (Sandbox Code Playgroud)

如果我正确理解有关"未指定函数参数顺序"的C++规则,则此代码不安全.如果B构造函数的第二个参数首先使用移动构造函数构造,那么a现在包含一个nullptr表达式a->x将触发未定义的行为(可能是段错误).如果首先构造第一个参数,那么一切都将按预期工作.

如果这是一个正常的函数调用,我们可以创建一个临时函数:

auto x = a->x
B b{x, std::move(a)};
Run Code Online (Sandbox Code Playgroud)

但是在类初始化列表中,我们没有自由创建临时变量.

假设我无法改变B,有没有可能的方法来实现上述目标?即unique_ptr在不创建临时的情况下解除引用并移动相同的函数调用表达式?

如果您可以更改B构造函数但不添加新方法,该setX(int)怎么办?那会有帮助吗?

谢谢

c++ initialization move-semantics unspecified-behavior c++11

49
推荐指数
3
解决办法
2789
查看次数

为什么`std :: stringstream :: stringstream(std :: string &&)`不存在?

我希望stringstream有一个构造函数窃取其初始内容string&&.STL中通常不存在这样的种间"移动构造函数"吗?如果没有,为什么不呢?

c++ stringstream rvalue-reference move-semantics c++17

48
推荐指数
2
解决办法
2145
查看次数