标签: move-semantics

移动构造函数是否在C++中调用了两次?

看看这段代码:

class Foo
{
public:

    string name;

    Foo(string n) : name{n}
    {
        cout << "CTOR (" << name << ")" << endl;
    }

    Foo(Foo&& moved)
    {
        cout << "MOVE CTOR (moving " << moved.name << " into -> " << name << ")" << endl;

        name = moved.name + " ###";
    }

    ~Foo()
    {
        cout << "DTOR of " << name << endl;
    }
};

Foo f()
{
    return Foo("Hello");
}

int main()
{
    Foo myObject = f();

    cout << …
Run Code Online (Sandbox Code Playgroud)

c++ move move-constructor move-semantics c++11

23
推荐指数
2
解决办法
1567
查看次数

移动唯一指针 - cppreference 上的未定义行为?

我对此有一个后续问题:Move unique_ptr: Reset the source vs. destroy the old object

为了快速总结原始问题,cppreference上有以下示例代码:

struct List
{
    struct Node
    {
        int data;
        std::unique_ptr<Node> next;
    };
 
    std::unique_ptr<Node> head;
 
    ~List()
    {
        // destroy list nodes sequentially in a loop, the default destructor
        // would have invoked its `next`'s destructor recursively, which would
        // cause stack overflow for sufficiently large lists.
        while (head)
            head = std::move(head->next);
    }
 
    ...
};
Run Code Online (Sandbox Code Playgroud)

答案告诉我,析构函数中的循环就所包含的原始指针而言是明确定义的,因为unique_ptr::operator=(unique_ptr&& other)被定义为 call ,这保证了在删除所持有的 raw_pointer 之前reset(other.release())提取原始指针。otherthis

我相信 cppreference …

c++ unique-ptr language-lawyer move-semantics

23
推荐指数
1
解决办法
969
查看次数

当最后一次使用可移动对象时,编译器会自动使用移动语义吗?

我最近一直在研究右值参考,并得出结论,在任何地方使用pass-by-value进行完整的对象复制是非常有利的(为了完整的理由,请参阅例如如何在添加rvalue参考运算符时减少冗余代码重载?要速度?按值传递!),因为编译器可以自动在如情况下优化复制走f(std::move(a));,其中f被定义为void f(A a);.

传递价值的一个负面后果是,std::move即使在简单的情况下,所有代码都会被弄乱,例如:

void Object::value(A a) 
{
    value_ = std::move(a);
}
Run Code Online (Sandbox Code Playgroud)

显然,如果我只写下面的内容:

void Object::value(A a) 
{
    value_ = a;
}
Run Code Online (Sandbox Code Playgroud)

a即使没有提示,编译器也应该很难识别出它的生命周期即将结束,并且不会使用额外的副本来惩罚我.事实上,即使在复杂的函数中,编译器也应该能够识别它.

问题:

  1. C++ 0x标准是否允许此优化?

  2. 编译器是否使用它?即使在复杂的情况下,即函数由多行组成?

  3. 这种优化的可靠性如何,即我希望编译器能够像我期望编译器应用返回值优化那样使用它吗?

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

22
推荐指数
1
解决办法
1585
查看次数

Initializer-list-构造不可复制(但可移动)对象的向量

可以将push_back不可复制但可移动类型的rvalues转换为该类型的向量:

#include <vector>

struct S
{
    S(int);
    S(S&&);
};

int main()
{
    std::vector<S> v;
    v.push_back(S(1));
    v.push_back(S(2));
    v.push_back(S(3));
}
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试初始化列表构造具有相同rvalues的向量时,我得到关于所需的复制构造函数的错误:

#include <vector>

struct S
{
    S(int);
    S(S&&);
};

int main()
{
    std::vector<S> v = {S(1), S(2), S(3)};
}
Run Code Online (Sandbox Code Playgroud)

我在GCC 4.7中遇到以下错误:

In file included from include/c++/4.7.0/vector:63:0,
                 from test.cpp:1:
include/c++/4.7.0/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = S, _Args = {const S&}]':
include/c++/4.7.0/bits/stl_uninitialized.h:77:3:   required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const S*, _ForwardIterator = S*, …
Run Code Online (Sandbox Code Playgroud)

c++ vector initializer-list move-semantics c++11

22
推荐指数
4
解决办法
3305
查看次数

在多个return语句的情况下,返回`std :: move`是否合理?

我知道回归通常不是一个好主意std::move,即

bigObject foo() { bigObject result; /*...*/ return std::move(result); }
Run Code Online (Sandbox Code Playgroud)

而不是简单的

bigObject foo() { bigObject result; /*...*/ return result; }
Run Code Online (Sandbox Code Playgroud)

因为它妨碍了返回值优化.但是在具有多个不同回报的函数的情况下,特别是类似的东西

class bar {
  bigObject fixed_ret;
  bool use_fixed_ret;
  void prepare_object(bigObject&);
 public:
  bigObject foo() {
    if(use_fixed_ret)
      return fixed_ret;
     else{
      bigObject result;
      prepare_object(result);
      return result;
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

我认为在这样的函数中,正常的返回值优化是不可能的,所以投入是一个好主意

      return std::move(result);
Run Code Online (Sandbox Code Playgroud)

在这里,或者我应该做什么(IMO丑陋,但这是有争议的)

  bigObject foo() {
    bigObject result;
    if(use_fixed_ret)
      result = fixed_ret;
     else{
      prepare_object(result);
    }
    return result;
  }
Run Code Online (Sandbox Code Playgroud)

c++ move-semantics return-value-optimization c++11

22
推荐指数
1
解决办法
6569
查看次数

(缺少)C++ 11移动语义的性能改进

我已经写了很长一段时间的C++ 11代码了,并没有对它进行任何基准测试,只是期望像移动语义这样的矢量操作现在"只是更快".因此,当实际使用GCC 4.7.2和clang 3.0(Ubuntu 12.10 64位上的默认编译器)进行基准测试时,我得到了非常不满意的结果.这是我的测试代码:

编辑:至于张贴@DeadMG和@ronag的(好)的答案,我从改变的元素类型std::string,以my::string不具有swap(),并且所有的内部串大(200-700字节),因此他们不应该SSO 的受害者.

编辑2: COW是原因.由伟大的意见再次改编代码,更改从存储std::stringstd::vector<char>和离开了复制/移动onstructors(让编译器生成它们来代替).没有COW,速度差异实际上是巨大的.

编辑3:编译时重新添加以前的解决方案-DCOW.这使得内部存储成为std::string而不是std::vector<char>@chico所要求的.

#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <functional>

static std::size_t dec = 0;

namespace my { class string
{
public:
    string( ) { }
#ifdef COW
    string( const std::string& ref ) : str( ref ), val( dec % 2 ? - ++dec : ++dec ) …
Run Code Online (Sandbox Code Playgroud)

c++ gcc clang move-semantics c++11

22
推荐指数
1
解决办法
4409
查看次数

如果std :: move将导致意外的副本,则强制编译时错误?

在他的2013年GoingNative演讲中,Scott Meyers指出,std::move并不能保证生成的代码实际上会执行一个动作.

例:

void foo(std::string x, const std::string y) {
  std::string x2 = std::move(x); // OK, will be moved
  std::string y2 = std::move(y); // compiles, but will be copied
}
Run Code Online (Sandbox Code Playgroud)

这里,不能应用移动构造函数,但由于重载分辨率,将使用普通的复制构造函数.这个后备选项对于向后兼容C++ 98代码可能是至关重要的,但在上面的例子中,它很可能不是程序员想要的.

有没有办法强制调用移动构造函数?

例如,假设您要移动一个巨大的矩阵.如果您的应用程序确实依赖于要移动的Matrix,那么如果无法移动则立即获得编译错误会很棒.(否则,您可能会通过单元测试轻松地解决性能问题,并且只能在进行一些分析后才能发现.)

让我们称之为保证行动strict_move.我希望能够编写这样的代码:

void bar(Matrix x, const Matrix y) {
  Matrix x2 = strict_move(x); // OK
  Matrix y2 = strict_move(y); // compile error
}
Run Code Online (Sandbox Code Playgroud)

可能吗?

编辑:

谢谢你的答案!有一些合理的要求澄清我的问题:

  • 如果strict_move输入是const,应该失败吗?
  • 如果strict_move结果不会导致实际的移动操作(即使副本可能像移动一样快),也应该失败,例如,const complex<double>
  • 都?

我最初的想法非常含糊:我认为Scott Meyers的例子非常令人担忧,所以我想知道是否有可能让编译器阻止这种非预期的副本.

Scott Meyers在他的演讲中提到,一般的编译器警告不是一种选择,因为它会导致大量误报.相反,我想与编译器进行通信,例如"我100%确定这必须始终导致移动操作,并且副本对于此特定类型来说太昂贵".

因此,我会毫不客气地说,strict_move两种情况都应该失败.与此同时,我不确定什么是最好的.我没有考虑的另一个方面是 …

c++ move-semantics c++11

22
推荐指数
3
解决办法
1677
查看次数

什么是ref-qualifier`const &&`的用法?

在上一个问题之后,我一直在研究ref-qualifiers.

给出下面的代码示例;

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

struct A {
  std::string abc = "abc";
  std::string& get() & {
    std::cout << "get() &" << std::endl;
    return abc;
  }
  std::string get() && {
    std::cout << "get() &&" << std::endl;
    return std::move(abc);
  }
  std::string const& get() const & {
    std::cout << "get() const &" << std::endl;
    return abc;
  }
  std::string get() const && {
    std::cout << "get() const &&" << std::endl;
    return abc;
  }
};

int main()
{
  A a1;
  a1.get();
  const …
Run Code Online (Sandbox Code Playgroud)

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

22
推荐指数
3
解决办法
4824
查看次数

移动分配比复制分配慢 - 错误,功能还是未指定?

我最近意识到在C++ 11中添加移动语义(或者至少我的实现,Visual C++)已经积极地(并且非常显着地)打破了我的一个优化.

请考虑以下代码:

#include <vector>
int main()
{
    typedef std::vector<std::vector<int> > LookupTable;
    LookupTable values(100);  // make a new table
    values[0].push_back(1);   // populate some entries

    // Now clear the table but keep its buffers allocated for later use
    values = LookupTable(values.size());

    return values[0].capacity();
}
Run Code Online (Sandbox Code Playgroud)

我遵循这种模式来执行容器回收:我将重新使用相同的容器而不是销毁和重新创建它,以避免不必要的堆释放和(立即)重新分配.

在C++ 03上,这很好用 - 这意味着这段代码用于返回1,因为向量是按元素复制的,而它们的底层缓冲区保持原样.因此,我可以修改每个内部向量,因为它知道它可以使用与之前相同的缓冲区.

然而,在C++ 11上,我注意到这会导致右侧移动到左侧,这对左侧的每个向量执行元素移动分配.这反过来导致向量丢弃其旧缓冲区,突然将其容量减少到零.因此,由于堆分配/释放过多,我的应用程序现在会大大减慢速度.

我的问题是:这种行为是一个错误,还是故意的?是否甚至由标准指定?

更新:

我刚刚意识到这种特定行为的正确性可能取决于是否a = A()可以使指向元素的迭代器无效a.但是,我不知道移动赋值的迭代器失效规则是什么,所以如果你知道它们,你的答案中可能值得一提.

c++ performance memory-management move-semantics c++11

22
推荐指数
2
解决办法
1015
查看次数

将std :: unique_ptr推回std :: vector时,编译器不会失败

一个unique_ptr不能被推回到一个std::vector,因为它是不可复制的,除非std::move被使用。但是,让我们F使用一个返回a的函数unique_ptr,然后std::vector::push_back(F())允许该操作。下面是一个示例:

#include <iostream>
#include <vector>
#include <memory>

class A {
  public:
    int f() { return _f + 10; }

  private:
    int _f = 20;
};

std::unique_ptr<A> create() { return std::unique_ptr<A>(new A); }


int main() {
  std::unique_ptr<A> p1(new A());

  std::vector< std::unique_ptr<A> > v;

  v.push_back(p1); // (1) This fails, should use std::move

  v.push_back(create()); // (2) This doesn't fail, should use std::move?

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

(2)允许,但(1)不允许。这是因为返回的值被隐式地移动了吗?

在中(2) …

c++ smart-pointers stdvector move-semantics

22
推荐指数
3
解决办法
1822
查看次数