如何解决说真的,复制和交换习语真的应该如何工作!我的代码失败
我听说过这种在 C++ 中实现 assign operator=()
的非常宣传的方式。
编辑:MVP,
版本 2:
a.out: main.cpp:52: int main(): Assertion `ptr == a.data()' Failed.
Aborted (core dumped)
这似乎是失败的地方,
没有复制和交换习语的copy operator=()
:
Data& operator=(const Data& rhs)
{
if(this != &data)
{
_size = rhs.size();
delete[] local_data;
local_data = new char[_size];
std::copy(rhs.data(),rhs.data() + rhs.size(),local_data);
}
return *this;
}
-
调用上述(非交换习语)实现的 Main.cpp,
int main(){ Data a("Some data"); auto ptr = a.data(); // Obtains a pointer to the original location a = Data("New data"); // When a is modified,this modification should effect the 'ptr' assert(ptr == a.data()); // Succeeds return 0; }
同上,除了复制和交换习语:
void swap(Data& rhs) noexcept
{
std::swap(_size,rhs.size());
std::swap(local_data,rhs.data());
}
Data& operator=(const Data& rhs)
{
Data tmp(data);
swap(data);
return *this;
}
2:使用交换习语实现:
int main(){
Data a("Some data");
auto ptr = a.data(); // Obtains a pointer to the original location
a = Data("New data"); // When a is modified,this modification should effect the 'ptr'
assert(ptr == a.data()); // Fail
return 0;
}
我观察到,有清理。但是,copy & Swap Idiom 的干净和简单的实现应该在这里失败。而且,我知道确实会发生一些运行时开销。但是,一般来说,复制和交换习语似乎更简洁、更好。
编辑:我知道自我分配问题,这应该有助于解决这个问题。自赋值在大多数程序中极为罕见,因此即使检查几乎总是错误的,显式检查也会为每个自赋值增加少量成本。
Sutter & Alexandrescu 展示了一个用交换成员编写的赋值运算符。这对自赋值是安全的,异常安全,并重用复制构造函数。
版本 2 的完整代码:
#include <iostream>
#include <cassert>
using namespace std;
class Data
{
private:
char* local_data;
int _size = 0;
inline int length(const char* str)
{
int n = 0;
while(str[++n] != '\0');
return n;
}
public:
Data() {
local_data = new char[_size];
}
Data(const char* cdata) : _size { length(cdata) }{
local_data = new char[_size];
std::copy(cdata,cdata + _size,local_data);
}
int size() const { return _size; }
const char* data() const { return local_data; }
void swap(Data& rhs) noexcept
{
std::swap(_size,rhs._size);
std::swap(local_data,rhs.local_data);
}
Data& operator=(const Data& data)
{
Data tmp(data);
swap(tmp);
return *this;
}
};
int main()
{
Data a("Some data");
auto ptr = a.data(); // Obtains a pointer to the original location
a = Data("New data"); // When a is modified,this modification should effect the 'ptr' (char*)
assert(ptr == a.data()); // Fails
return 0;
}
解决方法
主要问题是您似乎误解了对 res.flatten()
的修改是如何传播(或不传播)到 a.local_data
的。
让我们逐个陈述:
-
首先我们有
ptr
这给了我们类似的东西
Data a("Some data");
-
然后我们将指针“复制”到变量
+--------------+ +-------------+ | a.local_data | --> | "Some data" | +--------------+ +-------------+
中:ptr
这给了我们类似的东西
auto ptr = a.data();
-
在下一个语句中发生两件事:
-
首先使用
+--------------+ | a.local_data | --\ +--------------+ \ +-------------+ >--> | "Some data" | +-----+ / +-------------+ | ptr | -----------/ +-----+
创建一个新的临时对象:Data("New data")
-
然后在第一个版本中,您在复制赋值运算符中使用
+--------------+ | a.local_data | --\ +--------------+ \ +-------------+ >--> | "Some data" | +-----+ / +-------------+ | ptr | -----------/ +-----+ +------------------+ +------------+ | temporary_object | --> | "New data" | +------------------+ +------------+
和delete[]
会发生这种情况:new[]
然后临时对象被破坏,留下:
+--------------+ +------------+ | a.local_data | --> | "New data" | +--------------+ +------------+ +-----+ | ptr | --> ??? +-----+ +------------------+ +------------+ | temporary_object | --> | "New data" | +------------------+ +------------+
此处指针
+--------------+ +------------+ | a.local_data | --> | "New data" | +--------------+ +------------+ +-----+ | ptr | --> ??? +-----+
的值不再有效! -
在复制和交换版本中会发生其他事情:
ptr
然后临时对象被破坏,让你再次:
+--------------+ +------------+ | a.local_data | --> | "New data" | +--------------+ +------------+ +-----+ | ptr | ---------------\ +-----+ \ +-------------+ >--> | "Some data" | +------------------+ / +-------------+ | temporary_object | --/ +------------------+
和以前一样,
+--------------+ +------------+ | a.local_data | --> | "New data" | +--------------+ +------------+ +-----+ | ptr | --> ??? +-----+
的值不再有效。
-
然而,重要的是 ptr
和 ptr
之间的脱节。您可以修改一个,但另一个不会被修改。这当然会导致断言失败。
在您的示例中,它适用于第一种情况是巧合,因为内存分配器似乎正在重用传递给 a.local_data
的内存。这当然不能保证总是或什至重复发生。作为打破第一个“工作”示例的可能方法,尝试使用更长字符串创建一个新对象,如
delete[]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。