首先请确保您知道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;
};
只有界面,而实施很容易。
我的代码是这样的:
auto_ptr<int> foo()
{
auto_ptr<int> p(new int(1));
return p;
}
int main()
{
auto_ptr<int> p;
p = foo();
return 0;
}
在我看来,我的测试代码无法通过编译器。但是它通过了,当我运行它时,它被删除了两次。
我跟踪汇编代码并找到如下所示的流程,内存地址总是低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 =()?
我添加了1st 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&amp;'”。
那是钥匙!那我需要找到为什么!
当用户没有为类类型定义operator =时,编译器将生成一个。并与其他运营商进行比较=,选择一个更特别的运营商!
解决!想想你的所有答案!感谢您的所有评论!
答案 0 :(得分:1)
我不确定我是否正确理解了您的问题,但您的界面确实不定义了 copy 赋值运算符(也不是副本) 构造函数),因为&#34; 模板复制op =&#34;不是真正的副本op =(&#34;模板副本ctor&#34;不是真正的副本ctor)。
这是一个显示问题的简单示例:
#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&)
,即真正的 copy 赋值运算符,并且因为我们已经不声明了它(只有一个 template version)编译器自动生成它(它执行成员分配,因此调用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
成员(不释放源代码)。< / p>