gpt4 book ai didi

c++ - 按值传递不调用移动构造函数

转载 作者:太空狗 更新时间:2023-10-29 23:08:17 25 4
gpt4 key购买 nike

我有以下小类:

/// RAII wrapper for a Lua reference
class reference
{
public:
/// Construct empty reference
reference() : m_L(NULL), m_ref(LUA_NOREF) {}

/// Construct reference from Lua stack
reference(lua_State* L, int i = -1) : m_L(L) {
lua_pushvalue(L, i);
m_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}

/// Destructor
~reference() {
if (m_L) luaL_unref(m_L, LUA_REGISTRYINDEX, m_ref);
}

/// Copy constructor
reference(const reference& r) : m_L(r.m_L) {
r.push();
m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX);
}

/// Move constructor
reference(reference&& r) : m_L(r.m_L), m_ref(r.m_ref) {
r.m_L = NULL; // make sure r's destructor is NOP
}

/// Assignment operator
reference& operator=(reference r) {
swap(r, *this);
return *this;
}

/// Swap with other reference
friend void swap(reference& a, reference& b)
{
std::swap(a.m_L, b.m_L);
std::swap(a.m_ref, b.m_ref);
}

void push() const { lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_ref); }

private:
lua_State* m_L;
int m_ref;
};

请注意,赋值运算符是使用 copy-and-swap idiom 实现的并且是 supposed调用移动构造函数,如果与右值一起使用。

但是,引用 r; r = reference(L); 在进入赋值运算符之前调用复制构造函数。为什么,为什么?

写作 two assignment operators帮助:

    /// Assignment operator
reference& operator=(const reference& r) {
reference copy(r);
swap(copy, *this);
return *this;
}

/// Move assignment operator
reference& operator=(reference&& r) {
swap(r, *this);
return *this;
}

但是,代价是禁用复制省略。

按值传递不是应该按预期在这里工作吗?还是我的编译器(Mac 上的 Clang)坏了?

更新:

下面的小测试用例可以正常工作:

#include <iostream>

using namespace std;

struct resource
{
resource(int i=1) : i(i) { print(); }
~resource() { print(); i = 0; }

void print() const
{
cout << hex << " " << uint16_t(uintptr_t(this)) << ") " << dec;
}

int i;
};

resource* alloc_res()
{
cout << " (alloc_res";
return new resource(0);
}

resource* copy_res(resource* r)
{
cout << " (copy_res";
return new resource(r->i);
}

void free_res(resource* r)
{
if (r) cout << " (free_res";
delete r;
}

struct Test
{
void print() const
{
cout << hex << " [&=" << uint16_t(uintptr_t(this))
<< ", r=" << uint16_t(uintptr_t(r)) << "] " << dec;
}

explicit Test(int j = 0) : r(j ? alloc_res() : NULL) {
cout << "constructor"; print();
cout << endl;
}

Test(Test&& t) : r(t.r) {
cout << "move"; print(); cout << "from"; t.print();
t.r = nullptr;
cout << endl;
}

Test(const Test& t) : r(t.r ? copy_res(t.r) : nullptr) {
cout << "copy"; print(); cout << "from"; t.print();
cout << endl;
}

Test& operator=(Test t) {
cout << "assignment"; print(); cout << "from"; t.print(); cout << " ";
swap(t);
return *this;
cout << endl;
}

void swap(Test& t)
{
cout << "swapping"; print();
cout << "and"; t.print();
std::swap(r, t.r);
cout << endl;
}

~Test()
{
cout << "destructor"; print();
free_res(r);
cout << endl;
}

resource* r;
};

int main()
{
Test t;
t = Test(5);
}

如果使用 clang++ --std=c++11 -O0 -fno-elide-constructors test.cpp -o test 编译,移动构造函数被调用。 (感谢转换,本杰明林德利)

现在的问题是:为什么它现在起作用了?有什么区别?

最佳答案

没有合法的 C++11 情况会导致在 r = reference(L); 中调用复制构造函数。

这实际上等同于 r.operator =(reference(L));。由于 operator= 按值获取其参数,因此会发生以下两种情况之一。

  1. 临时文件将用于构造值。由于它是临时的,它将优先调用reference的移动构造函数,从而导致移动。
  2. 临时变量将被直接省略到值参数中。禁止复制或移动。

在此之后,operator= 将被调用,它不会在内部进行任何复制。

所以这看起来像是一个编译器错误。

关于c++ - 按值传递不调用移动构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10299439/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com