标签: move-semantics

调用 std::move 而不使用移动构造函数或移动赋值

我们知道 std::move实际上并没有移动任何东西。它只是将左值引用 (&) 转换为右值引用 (&&)。

那么在下面的例子中,复制构造函数是如何调用的呢?如果没有移动构造函数,那么构造使用 std::move() 的对象如何依靠复制构造函数?变量的绑定究竟是如何b发生的?

struct Test {
  // Default constructor
  Test() {
    std::cout << "Constructor is called." << std::endl;
    mValue = 0;
  }
  
  // Copy constructor
  Test(const Test& rhs) {
    std::cout << "Copy Constructor is called." << std::endl;
    mName = rhs.mName;
    mValue = rhs.mValue;
  }
    
  std::string mName;
  int mValue;
};

int main() {
  Test a;
  Test b = std::move(a);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Constructor is called.
Copy Constructor is called.
Run Code Online (Sandbox Code Playgroud)

c++ move-semantics c++11

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

使用移动元素调整向量大小是否正确?

我试图理解移动语义的通用规则。特别是容器和包含的元素。

原因是我试图在所有权和迭代器失效的背景下理解移动。为此,我将经历一些复杂性不断增加的案例,涉及典型容器、通用包含类型T、通用gf函数。(也许一个重要的额外细节是,f实际上可能会或可能不会执行移动操作,或者它可能在运行时是偶然的。)

这个想法是引入案例3,这是这个问题的核心。

案例0

首先是一个相当没有争议的案例,这是可以的:

std::vector<T> v(100, t);
f(std::move(v));
v = make_a_vector();
Run Code Online (Sandbox Code Playgroud)

情况1

然而,移动后使用可能是臭代码

std::vector<T> v(100, t);
f(std::move(v));
g(v);
Run Code Online (Sandbox Code Playgroud)

我想大多数人都同意上面的做法是不行的。规则是(据我所知)移动后的唯一操作应该是赋值。我认为这尤其是因为它没有记录(未定义但有效的状态)移出向量的状态是什么(或者即使它被移动了)。因此,充其量v是空的,最坏的v情况是未指定的状态,因此g可以在此范围内执行未指定的操作。

案例2:

std::vector<T> v(100, t);
f(std::move(v));
v.resize(120);
Run Code Online (Sandbox Code Playgroud)

这是对的吗?这不是一项任务,但resize没有先决条件。(发现这个Can I resize a vector that was moving from?

案例3:

现在是真正棘手的情况。

std::vector<T> v(100);
h(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
v.resize(120);
Run Code Online (Sandbox Code Playgroud)

(这里,h是一个采用迭代器的函数,假设它隐式引用 range [iterator1, iterator2)

这是正确的代码吗?原因是.resize似乎要播放、移动、交换和复制类型为移出的对象T

总而言之,调整其元素已(可能)移出的向量的大小是否正确?


编辑:为了论证,让我们指定函数的签名,以防它们与答案相关:

template<class …
Run Code Online (Sandbox Code Playgroud)

c++ vector stdvector move-semantics

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

具有字符串成员的类的 C++ 移动构造函数

我用以下代码编写了一个类:

class Test {
public:
...
    Test( const Test &&that ) : i(that.i), s(std::move(that.s)) {
        cout << "move contructor." << endl;
    }
...
private:
    int i;
    std::string s;
};
Run Code Online (Sandbox Code Playgroud)

如果我反汇编生成的代码,我会看到:

        .type   Test::Test(Test const&&), @function
Test::Test(Test const&&):
...
       call    std::remove_reference<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type&& std::move<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
        movq    %rax, %rsi
        movq    %rbx, %rdi
.LEHB3:
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@PLT
Run Code Online (Sandbox Code Playgroud)

它的调用让我感到惊讶,basic_string<...>::basic_string( basic_string<...> const&)因为我期望调用 basic_string 的移动构造函数basic_string<...>::basic_string( basic_string<...> &&)

我以错误的方式实现了移动构造函数?

c++ move-semantics

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

从 unique_ptr 移动到堆栈变量

是否可以T从 a 创建堆栈变量(具有移动构造函数的类型)std::unique_ptr<T>

我尝试过类似的东西

std::unique_ptr<T> p = ext_get_my_pointer();   // external call returns a smart pointer
T val{std::move(*p.release())};                // I actually need a stack variable
Run Code Online (Sandbox Code Playgroud)

但它看起来很难看,并且显然会造成内存泄漏。但不知道为什么。

c++ unique-ptr move-semantics

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

将 const 限定对象传递给“std::move”

通过在PVS-Studio中进行一些代码分析,它给了我一些警告消息。

我在头文件中有以下语句:

constexpr int MIN_ALLOWED_Y { 0 };
Run Code Online (Sandbox Code Playgroud)

在源文件中:

std::make_pair<const int, const int>( std::move( MIN_ALLOWED_Y ), std::move( MAX_ALLOWED_Y ) )
Run Code Online (Sandbox Code Playgroud)

在上面的表达式中,我曾经std::move转换MIN_ALLOWED_Y为 xvalue,因为我认为std::make_pair只接受右值;

// from https://en.cppreference.com/w/cpp/utility/pair/make_pair

template< class T1, class T2 >
constexpr std::pair<V1,V2> make_pair( T1&& t, T2&& u );
Run Code Online (Sandbox Code Playgroud)

但我收到如下警告消息:

V833 Passing the const-qualified object 'MIN_ALLOWED_Y' to the 'std::move' function disables move semantics.
Run Code Online (Sandbox Code Playgroud)

这是有效的警告吗?如果是这样那我该怎么办?我应该删除std::move(也许在这种情况下它是多余的?)?

更好的问题是哪里不应该使用std::move

c++ static-code-analysis move-semantics pvs-studio

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

如何将没有自定义删除器的 unique_ptr 移动到另一个具有自定义删除器的 unique_ptr?

#include <memory>
#include <functional>
#include <iostream>

struct TestStruct {
    int a = 100;
};

struct StructDeleter {
    void operator()(TestStruct *ptr) const {
        delete ptr;
    }
};

std::unique_ptr<TestStruct, StructDeleter> MakeNewStruct() {
    std::unique_ptr<TestStruct> st(new TestStruct());

    std::unique_ptr<TestStruct, StructDeleter> customDeleterSt(std::move(st));
    std::cout << customDeleterSt->a << std::endl;
    return customDeleterSt;
}

int main() {
    auto a = MakeNewStruct();
    std::cout << a->a << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码无法编译,如何st移至customDeleterSt?我st从创建界面获得了一个 unique_ptr st,并使用自定义删除器对用户隐藏了 的实现st,那么如何将没有自定义删除器的 unique_ptr 移动到具有自定义删除器的 unique_tr 呢?

谢谢你的帮助!

c++ unique-ptr move-semantics

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

在向量返回上移动语义行为

我一直在玩c ++ 11移动语义

在代码中......

#include <vector>
#include <string>

std::vector<std::string> GetNewVector()
{
  std::vector<std::string> newVec; 
  newVec.push_back(std::string("hello")); //(1)
  newVec.push_back(std::string("whey")); //(2)

  return newVec;
}

int main(int argc, char* argv[])
{
  std::vector<std::string> vec = GetNewVector();
}
Run Code Online (Sandbox Code Playgroud)

在点(1),当对象移动到向量中时,调用"hello"对象的移动构造函数.

在第(2)点,首先再次调用"hello"的移动构造函数,(我假设这是向量重新分配的位置),然后调用"whey"移动构造函数.

这完全符合预期,但是我期望在结束时返回向量时再次移动对象GetNewVector(),但是移动构造函数不会再次被调用.我的猜测是RVO正在发生,但是当我在调试模式下运行Visual Studio(2k10)时,我不确定是否会发生这种情况?

如果可以执行RVO,那么它将优先于使用移动构造函数吗?

c++ move-semantics c++11

0
推荐指数
1
解决办法
259
查看次数

移动构造函数orphaning内存?

我正在看这个显示移动构造函数的答案:

/sf/answers/217698701/

#include <cstring>
#include <algorithm>

class string
{
    char* data;

public:

    string(const char* p)
    {
        size_t size = strlen(p) + 1;
        data = new char[size];
        memcpy(data, p, size);
    }

    ~string()
    {
        delete[] data;
    }

    string(const string& that)
    {
        size_t size = strlen(that.data) + 1;
        data = new char[size];
        memcpy(data, that.data, size);
    }

};
Run Code Online (Sandbox Code Playgroud)

然后介绍一个移动构造函数:

string(string&& that)   // string&& is an rvalue reference to a string
{
    data = that.data;
    that.data = 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我们分配指向data该值的指针that.data,肯定这会导致内存泄漏,该new …

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

0
推荐指数
1
解决办法
123
查看次数

当移动语义与std :: move一起使用时?

在这个例子中,移动语义是如何工作的:

struct test {
    int ii[10];
    int i;
};

test f() {
    test a;
    std::cout << "[1] " << &a << std::endl;
    return a;
}

int main()
{
  test x (f());
  std::cout << "[2] " << &x << std::endl;
  test x1 (std::move(x));
  std::cout << "[3] " << &x1;
}
Run Code Online (Sandbox Code Playgroud)

输出:

[1] 0x7fff50ac70c0
[2] 0x7fff50ac70c0
[3] 0x7fff50ac70f0
Run Code Online (Sandbox Code Playgroud)

为什么x是使用f()的返回值构造的,但是x1的地址与x不同?

编辑

struct test {
  std::string s;
}

[...]

std::cout << (*void)&x.s[0];
Run Code Online (Sandbox Code Playgroud)

我想最终我明白了.现在地址是一样的.

c++ move-semantics c++11

0
推荐指数
1
解决办法
88
查看次数

是否有可能避免重复元组上的std :: move()?

假设我有一个元组和一个函数:

typedef std::tuple< std::unqiue_ptr<int>, std::unqiue_ptr<char> > SomeTuple;          
void someFunction( std::unqiue_ptr<int>, std::unqiue_ptr<char> );
Run Code Online (Sandbox Code Playgroud)

所以在辅助函数中我将元组展开为参数:

void unroll( SomeTuple &t )
{
    someFunction( std::get<0>( std::move( t ) ), std::get<1>( std::move( t ) ) );
}
Run Code Online (Sandbox Code Playgroud)

它有效,但我想避免重复std::move多次.天真的解决方案如:

void unroll( SomeTuple &t )
{
    auto &&rt = std::move( t );
    someFunction( std::get<0>( rt ), std::get<1>( rt ) );
}
Run Code Online (Sandbox Code Playgroud)

显然不起作用,因为rt是一个lvalue.那么有没有办法避免std::move()每次重复多次std::get

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

0
推荐指数
1
解决办法
193
查看次数