gpt4 book ai didi

c++ - 尝试根据 move 赋值编写 move 构造函数

转载 作者:搜寻专家 更新时间:2023-10-31 00:37:25 24 4
gpt4 key购买 nike

所以玩转 move 语义。

所以我第一次看这个是这样的:

 class String
{
char* data;
int len;
public:
// Normal rule of three applied up here.
void swap(String& rhs) throw()
{
std::swap(data, rhs.data);
std::swap(len, rhs.len);
}
String& operator=(String rhs) // Standard Copy and swap.
{
rhs.swap(*this);
return *this;
}

// New Stuff here.
// Move constructor
String(String&& cpy) throw() // ignore old throw construct for now.
: data(NULL)
, len(0)
{
cpy.swap(*this);
}
String& operator=(String&& rhs) throw()
{
rhs.swap(*this);
return *this;
}
};

看着这个。我认为根据 Move 赋值定义 Move 构造函数可能是值得的。它有一个很好的对称性,我喜欢它,因为它看起来也很干(并且像 copy-and-swap )。

所以我将 Move Constructor 重写为:

         String(String&& cpy) throw() 
: data(NULL)
, len(0)
{
operator=(std::move(cpy));
}

但这会产生歧义错误:

String.cpp:45:9: error: call to member function 'operator=' is ambiguous
operator=(std::move(rhs));
^~~~~~~~~
String.cpp:32:13: note: candidate function
String& operator=(String rhs)
^
String.cpp:49:13: note: candidate function
String& operator=(String&& rhs) throw()
^
1 error generated.

因为我在传递参数时使用了 std::move(),所以我希望它能绑定(bind)到 Move 赋值运算符。我做错了什么?

最佳答案

What am I doing wrong?

尝试根据另一个来编写一个特殊成员函数的情况应该很少见。每个特殊成员通常都需要特别注意。 如果在使每个特殊成员尽可能高效的练习之后,您看到了合并代码的机会,那么,也只有在那时,才开始努力。

以在特殊成员之间整合代码为目标是错误的起点。

第 1 步。开始尝试使用 = default 编写您的特殊成员。

第2步,如果失败,则自定义每一个不能写的=default

第 3 步。编写测试以确认第 2 步是否有效。

第 4 步。完成第 3 步后,查看是否可以在不牺牲性能的情况下进行代码整合。这可能涉及编写性能测试。

直接跳到第 4 步很容易出错,并且通常会导致严重的性能损失。

这是您示例的第 2 步:

#include <algorithm>

class String
{
char* data;
int len;
public:
String() noexcept
: data(nullptr)
, len(0)
{}

~String()
{
delete [] data;
}

String(const String& cpy)
: data(new char [cpy.len])
, len(cpy.len)
{
std::copy(cpy.data, cpy.data+cpy.len, data);
}

String(String&& cpy) noexcept
: data(cpy.data)
, len(cpy.len)
{
cpy.data = nullptr;
cpy.len = 0;
}

String& operator=(const String& rhs)
{
if (this != &rhs)
{
if (len != rhs.len)
{
delete [] data;
data = nullptr;
len = 0;
data = new char[rhs.len];
len = rhs.len;
}
std::copy(rhs.data, rhs.data+rhs.len, data);
}
return *this;
}

String& operator=(String&& rhs) noexcept
{
delete [] data;
data = nullptr;
len = 0;
data = rhs.data;
len = rhs.len;
rhs.data = nullptr;
rhs.len = 0;
return *this;
}

void swap(String& rhs) noexcept
{
std::swap(data, rhs.data);
std::swap(len, rhs.len);
}
};

更新

应该注意的是,在 C++98/03 中,不能成功重载参数仅在按值和按引用之间不同的函数。例如:

void f(int);
void f(int&);

int
main()
{
int i = 0;
f(i);
}

test.cpp:8:5: error: call to 'f' is ambiguous
f(i);
^
test.cpp:1:6: note: candidate function
void f(int);
^
test.cpp:2:6: note: candidate function
void f(int&);
^
1 error generated.

添加 const 没有帮助:

void f(int);
void f(const int&);

int
main()
{
f(0);
}

test.cpp:7:5: error: call to 'f' is ambiguous
f(0);
^
test.cpp:1:6: note: candidate function
void f(int);
^
test.cpp:2:6: note: candidate function
void f(const int&);
^
1 error generated.

这些相同的规则适用于 C++11,并且在不修改右值引用的情况下进行了扩展:

void f(int);
void f(int&&);

int
main()
{
f(0);
}

test.cpp:7:5: error: call to 'f' is ambiguous
f(0);
^
test.cpp:1:6: note: candidate function
void f(int);
^
test.cpp:2:6: note: candidate function
void f(int&&);
^
1 error generated.

因此,给出以下结果也就不足为奇了:

String& operator=(String rhs);
String& operator=(String&& rhs) throw();

结果是:

String.cpp:45:9: error: call to member function 'operator=' is ambiguous
operator=(std::move(rhs));
^~~~~~~~~
String.cpp:32:13: note: candidate function
String& operator=(String rhs)
^
String.cpp:49:13: note: candidate function
String& operator=(String&& rhs) throw()
^
1 error generated.

关于c++ - 尝试根据 move 赋值编写 move 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19826045/

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