gpt4 book ai didi

c++ - 为什么 auto_ptr 行为异常

转载 作者:行者123 更新时间:2023-11-28 07:26:30 28 4
gpt4 key购买 nike

首先请确保您知道 std::auto_ptr 曾经有 3 个版本。

std::auto_ptr 的第一个版本如下所示:

template<class T>
class auto_ptr
{
public:
explicit auto_ptr(T *p = 0): pointee(p) {}

// copy constructor member
// template: initialize a new auto_ptr with any compatible auto_ptr
template<class U> auto_ptr(auto_ptr<U>& rhs): pointee(rhs.release()) {}

~auto_ptr() { delete pointee; }

// assignment operator
// member template assign from any compatible auto_ptr
template<class U> auto_ptr<T>& operator=(auto_ptr<U>& rhs)
{
if (&rhs != this)
{
reset(rhs.release());
}
return *this;
}

T& operator*() const { return *get(); }
T* operator->() const { return get(); }

// return value of current dumb pointer
T* get() const { return pointee; }

// relinquish ownership of current dumb pointer and return its value
T* release() { T* p = pointee; pointee = 0; return p; }

// delete owned pointer,assume ownership of p
void reset(T *p = 0)
{
if (p != pointee)
{
delete pointee;
pointee = p;
}
}
private:
T* pointee;
};

只有接口(interface),实现起来很简单。

我的代码是这样的:

auto_ptr<int> foo()
{
auto_ptr<int> p(new int(1));
return p;
}

int main()
{
auto_ptr<int> p;
p = foo();
return 0;
}

在我看来,我的测试代码无法通过编译器。但是它通过了,当我运行它时,它因删除 ponter 两次而中断。

我跟踪汇编代码,发现流程如下,内存地址简称为低16位。

ctor: f8e4    
new: 6bf0
ctor: f7d4

copy ctor: f7d4 -> f80c
dctor: f7d4 (NULL)
delete: 0

lea ecx, [ebp-0ECh] // f8e4: memory-> 6bf0

dctor: f80c (6bf0)
delete: 6bf0

dctor: f8e4 (6bf0) // twice delete

似乎代码:p = foo(); ctor 一个临时对象,它保存了 foo() 中新的内存。

关键是,为什么 p = foo() 只是改变 p.pointee,而不是调用 p.operator=() ?

我添加了第一个 auto_ptr 的实现。


与网友交谈,他指出mybe编译器生成:

auto_ptr<T>& operator=(auto_ptr<T>& rhs)

除了使用

template<class U> auto_ptr<T>& operator=(auto_ptr<U>& rhs);

我发现 std::auto_ptr 有两个 operator=。我测试手动将它添加到界面,同时编译器提示:“‘auto_ptr’无法转换为‘auto_ptr &’”。

这是关键!!!然后我需要找到原因!


当用户没有为类类型定义 operator= 时,编译器将生成一个。并与其他运算符=进行比较,选择一个更特殊的!

解决了!考虑你所有的答案!感谢您的所有评论!

最佳答案

我不确定我是否正确理解了您的问题,但您的界面实际上没有定义copy赋值运算符(也不是copy 构造函数),因为“模板复制 op=”不是真正的复制 op=(并且“模板复制构造函数”不是真正的复制构造函数)。

这里有一个简单的例子来说明这个问题:

#include <cstdio>
using std::puts;

struct M {
M& operator=(M const&) {
puts("M::operator=(M const&)");
return *this;
}
};

template<typename T> class Foo {
M m;
template<typename U> friend class Foo; // (needed for m = rhs.m; below)
public:
template<typename U> Foo& operator=(Foo<U> const& rhs) {
puts("[template] Foo<T>::operator=(Foo<U> const&)");
m = rhs.m; // calls M's op=
return *this;
}
};

int main() {
puts("===");
Foo<int> a;
Foo<double> b;
a = b;
puts("---");
Foo<int> c;
Foo<int> d;
c = d;
puts("===");
}

打印:

===
[template] Foo<T>::operator=(Foo<U> const&)
M::operator=(M const&)
---
M::operator=(M const&)
===

为什么第二个作业只有一行?那是因为 c = d;电话 Foo<int>::operator=(Foo<int> const&)即真正的复制赋值运算符,因为我们没有声明它(只有模板版本)编译器自动生成它(它做了成员分配,因此调用 M::operator= )。

因此,我必须将它显式添加到类中:

    // ...
Foo& operator=(Foo const& other) {
puts("[non-template] Foo<T>::operator=(Foo<T> const&)");
m = other.m;
return *this;
}
};

然后打印:

===
[template] Foo<T>::operator=(Foo<U> const&)
M::operator=(M const&)
---
[non-template] Foo<T>::operator=(Foo<T> const&)
M::operator=(M const&)
===

因此,在您的示例中,p = foo();不会调用您的用户定义 template<class U> auto_ptr<T>& operator=(auto_ptr<U>& rhs)但是隐式生成的版本只是分配了 pointee成员(不发布来源)。

关于c++ - 为什么 auto_ptr 行为异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18674845/

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