gpt4 book ai didi

c++ - 编写 move 复制和 move 赋值构造函数的有效方法

转载 作者:太空狗 更新时间:2023-10-29 20:44:39 26 4
gpt4 key购买 nike

下面的赋值和复制 move 构造函数是最高效的吗?如果有人有其他方式请告诉我?我的意思是 std::swap 怎么样?并且在下面的代码中通过复制构造函数调用赋值是安全的吗?

#include <iostream>
#include <functional>
#include <algorithm>
#include <utility>

using std::cout;
using std::cin;
using std::endl;
using std::bind;


class Widget
{

public:

Widget(int length)
:length_(length),
data_(new int[length])
{
cout<<__FUNCTION__<<"("<<length<<")"<<endl;
}

~Widget()
{
cout<<endl<<__FUNCTION__<<"()"<<endl;
if (data_)
{
cout<<"deleting source"<<endl;
}
else
{
cout<<"deleting Moved object"<<endl;
}

cout<<endl<<endl;
}

Widget(const Widget& other)
:length_(other.length_),
data_(new int[length_])
{
cout<<__FUNCTION__<<"(const Widget& other)"<<endl;
std::copy(other.data_,other.data_ + length_,data_);
}

Widget(Widget&& other)
/*
:length_(other.length_),
data_(new int[length_])*/
{
cout<<__FUNCTION__<<"(Widget&& other)"<<endl;
length_ = 0;
data_ = nullptr;
std::swap(length_,other.length_);
std::swap(data_,other.data_);
}

Widget& operator = (Widget&& other)
{
cout<<__FUNCTION__<<"(Widget&& other)"<<endl;

std::swap(length_,other.length_);
std::swap(data_,other.data_);

return *this;
}

Widget& operator = (const Widget& other)
{
cout<<__FUNCTION__<<"(const Widget& other)"<<endl;
Widget tem(other);
std::swap(length_,tem.length_);
std::swap(data_,tem.data_);

return *this;
}
int length()
{
return length_;
}

private:

int length_;
int* data_;
};



int main()
{
{
Widget w1(1);
Widget w2(std::move(Widget(2)));

w1 = std::move(w2);
}


cout<<"ENTER"<<endl;
cin.get();
return 0;
}

最佳答案

从效率 POV 来看看起来不错,但包含大量重复代码。我愿意

  • 为您的类实现一个 swap() 运算符。
  • 在声明的地方初始化 length_data_
  • 尽可能根据其他操作来实现操作。

可能想要使用std::memcpy 而不是std::copy 因为无论如何您正在处理原始数组。一些编译器会为你做这些,但可能不是全部......

这是您的代码的去重版本。注意只有 一个 地方需要知道 Widget 的两个实例是如何交换的。并且只有一个地方知道如何分配给定大小的 Widget。

编辑:您通常还希望使用依赖于参数的查找来定位交换,以防万一您有非原始成员。

编辑:整合了@Philipp 的建议,即让赋值运算符按值获取参数。这样,它既可以作为 move 赋值运算符,也可以作为复制赋值运算符。在 move 的情况下,不是说如果你传递一个临时的,它不会被复制,因为 move 构造函数,不是复制构造函数将被用来传递参数.

编辑:C++11 允许在右值上调用非成本成员,以与以前版本的标准兼容。这允许像 Widget(...) = someWidget 这样奇怪的代码可以编译。通过在声明之后放置 & 来使 operator= 需要 this 的左值可以防止这种情况发生。请注意,即使没有该限制,代码也是正确的,但它似乎是个好主意,所以我添加了它。

编辑:正如 Guillaume Papin 指出的那样,析构函数应该使用 delete[] 而不是普通的 delete。 C++ 标准要求通过 delete [] 删除通过 new [] 分配的内存,即它允许 new' 和 new []`使用不同的堆。

class Widget
{
public:
Widget(int length)
:length_(length)
,data_(new int[length])
{}

~Widget()
{
delete[] data_;
}

Widget(const Widget& other)
:Widget(other.length_)
{
std::copy(other.data_, other.data_ + length_, data_);
}

Widget(Widget&& other)
{
swap(*this, other);
}

Widget& operator= (Widget other) &
{
swap(*this, other);
return *this;
}

int length() const
{
return length_;
}

private:
friend void swap(Widget& a, Widget& b);

int length_ = 0;
int* data_ = nullptr;
};

void swap(Widget& a, Widget& b) {
using std::swap;
swap(a.length_, b.length_);
swap(a.data_, b.data_);
}

关于c++ - 编写 move 复制和 move 赋值构造函数的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12651063/

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