《C++标准程序库》里的auto_ptr的“转型操作”

J2eeLearner 2003-01-12 04:33:14
作者的代码在这里 :
http://www.josuttis.com/libbook/util/autoptr.hpp.html


C++标准程序库》的page 55,以及原文page 54 都提到了conversions(转型操作):

中文:
//
auto_ptr的剩余部分的内容(auot_ptr_ref以及相关函数)设计非常精致的技巧,使得我们能够拷贝和赋值non-const aut_ptr,但是不能拷贝和赋值const auto_ptr .这里面有两个要求:1) 必须将auto_ptr作为右值传递到函数中,或者有函数中返回,而auto_ptr是class,所以这里必须由构造函数完成 2)拷贝auto_ptr的时候,原指针必须放弃拥有全,所以也就需要修改原本的auto_ptr.

一般的构造函数当然可以拷贝右值,但是为了这点,必须把参数类型声明为reference to const object 。如果在auto_ptr中使用一般的copy构造函数,则我们必须将auto_ptr内部的指针定义为mutable。只有这样,才能在auto_ptr的构造函数中修改它.
//

英文:
//
The rest of the class auto.ptr (auxiliary type auto_ptr_ref and functions using it) consists of rather tricky conversions that enable you to use copy and assignment operations for nonconstant auto_ptrs but not for constant auto_ptrs (see page 44 for details). The following is a quick
explanation. We have the following two requirements:
1. It should be possible to pass auto_ptrs to and from functions as rvalues. Because auto_ptr is a class, this must be done using a constructor.
2. When an auto_ptr is copied, it is important that the source pointer gives up ownership. This requires that the copy modifies the source auto_ptr.

An ordinary copy constructor can copy an rvalue, but to do so it must declare its parameter as a reference to a const object. To use an ordinary constructor to copy an auto_ptr we would have to declare the data member containing the real pointer mutable so that it could be modified in the copy constructor. But this would allow you to write code that copies auto_ptr objects that were actually declared const, transferring their ownership in contradiction to their constant status.
//

问题:
1)拷贝构造函数里面的参数如作者说的,“必须为reference to const object”吗?
看我的程序!
2)如果不是,正如我程序中一样,没有了auto_ptr_ref的帮助,也照样可以实现“我们能拷贝和赋值none-const auto_ptr”,不能拷贝和赋只“const auto_ptr”!那么auto_ptr_ref还有必要么? 我哪儿考虑错了?

附我的程序:

#include <iostream>
using namespace std;

template <class _Tp> class auto_ptr {
private:
_Tp* _M_ptr;
public:
explicit auto_ptr(_Tp* __p = 0): _M_ptr(__p) {}
auto_ptr(auto_ptr& __a) : _M_ptr(__a.release()) {}
auto_ptr& operator=(auto_ptr& __a){
if (&__a != this) {
delete _M_ptr;
_M_ptr = __a.release();
}
return *this;
}
_Tp& operator*() const {
return *_M_ptr;
}
_Tp* release() {
_Tp* __tmp = _M_ptr;
_M_ptr = 0;
return __tmp;
}
~auto_ptr() { delete _M_ptr; }
};

class Helper
{
public:
Helper()
{
cout<<"Helper()"<<endl;
}
Helper(const Helper& t)
{
cout<<"Helper::Cotr"<<endl;
}
void say()
{
cout<<"Helper::say()"<<endl;
}
};

int main()
{

auto_ptr<Helper> p1(new Helper);
(*p1).say();
auto_ptr<Helper> p2(p1);
(*p2).say();

const auto_ptr<Helper> p3(new Helper);
auto_ptr<Helper> p4(p3); // wrong!

(*p3).say() ;
cin.get();
}



...全文
9 点赞 收藏 18
写回复
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhaohangcom 2003-03-21
`
回复
dzhcheng 2003-02-10
up
回复
merlinran 2003-02-08
在新帆新闻组上得到答案。还是自己脑子不灵光。

这种helper class的作法可值得好好学学。不知高人们是怎么想到这一办法的。可能也是灵感所至吧。
回复
zhaohangcom 2003-02-06
闲着
回复
huxw 2003-02-02
pat merlinran。;-)

A(A a){}这样的构造函数里面,a是怎么来的?
回复
earthharp 2003-02-02
.....
回复
merlinran 2003-01-28
什么意思?
永远不可能由自己构造自己,这是编译器和构造函数的使用方式所保证的。怎么可能出现无穷递归呢?
回复
earthharp 2003-01-26
想不通为何拷贝构造函数禁止by value,而拷贝赋值运算符允许。哪位能给个理由吗?
X::X(X); //fail
X::operator=(X); //success

这么简单的问题,你想想赋值是已有的对象,ctor是生成新对象。要是by value不是无穷递归吗?
回复
merlinran 2003-01-26
有点意思。以前看不太懂上面的讨论,后来把原书看到此地才明白。

temporary只能绑定到常量引用。如果使用传常量引用的方式拷贝,那就不能防止拷贝
用户定义的常量。

通过传值方式,可以实现temporary的拷贝。因此,将auto_ptr转型为auto_ptr_ref,
再作为参数传入构造函数。

注意以下两个声明的区别:
auto_ptr::auto_ptr(auto_ptr& _a); //[1]by reference
auto_ptr::auto_ptr(auto_ptr_ref _a); //[2]by value
因此[2]可以传递temporary,[1]却不行。

但为何不直接写成这样:
auto_ptr::auto_ptr(auto_ptr _a);
原因很简单:这不符合copy ctor的规则。标准说:X的copy ctor之第一个参数只能是
X&、const X&、volatile X&、const volatile X&四种形式,就是只能by reference。
那为何[2]可以by value呢?因为它不是copy ctor,只是converting ctor。

想不通为何拷贝构造函数禁止by value,而拷贝赋值运算符允许。哪位能给个理由吗?
X::X(X); //fail
X::operator=(X); //success

回复
J2eeLearner 2003-01-15
The 'auto_ptr_ref' is to enable rvalues to be copied but prevent 'const'
objects from being copied! For example:

std::auto_ptr<int> const p1(new int(17));
std::auto_ptr<int> const p2(p1); // ERROR: no ctor for 'const' objects
std::auto_ptr<int> p3(std::auto_ptr<int>(new int(17)); file://OK: copying rvalue

That is, non-const 'std::auto_ptr's, including rvalues, ie. temporaries, can
be copied (thereby transfering ownership) which is necessary in particular
when passing objects by value and, more importantly, when returning an object
from a function.


This is not at all about const correctness! It is about preventing 'const'
objects being modified under the hood, ie. preventing copying of 'const'
objects while also allowing copying of non-const objects, including those
which cannot be bound to a non-const reference, that is rvalues.


'std::auto_ptr' is not intended to be a reference counted pointer: Its sole
goal is automatic release of a resource in very specific cases (eg. to protect
against resource leaks in case of exceptions while returning a pointer).
Creating a reasonable reference counted pointer is non-trivial and took
several years to obtain a good implementation for Boost. One of the key
problems which could not be resolved prior to standardization is the
property of using an intrusive vs. a non-intrusive counter: either the counter
is located in the object itself (intrusive) or outside the object
(non-intrusive). Since 'int' does not have place for an intrusive count, it is
obvious that the counter has to be outside. However, for objects possibly
returning a reference counted pointer to themselves, the counter has to be
intrusive!

Since problems like this could not be resolved prior to standardisation (they
are now basically resolved for Boost's 'shared_ptr'), no reference counted
pointer was included in the standard library, although one was proposed: the
original proposal by Greg Colvin which added 'std::auto_ptr' also proposed
'std::rc_ptr', a reference counted pointer. However, the latter was dropped.


回复
J2eeLearner 2003-01-14
1)不带auto_ptr_ref, 从函数返回auto_ptr 应该还是可以的吧!
2)临时变量,确实 有点问题!
回复
J2eeLearner 2003-01-14
auto_ptr_ref is necessary to allow returning an auto_ptr from a function and
it be copied as a temporary. A non-const ref cannot take a temporary
parameter, although many compilers allow it.
回复
J2eeLearner 2003-01-13
这里有一个比较有意思的回复:
Unless I'm missing something, you are confusing the authors intention.

According to _your_ understanding:
Author want's to _enable_ copying of non-const auto_ptr but
_disable_ copying of const auto_ptr.

I don't think this is the intention. In my understanding the intention
is to _enable_ copying of _both_ const as well as non-const auto_ptr.

Let me summarize:-

1. Author want's to use ownership based auto_ptr - ie: every time the
pointer is copied, it must release internal ptr.

2. Release is non-constant function.

3. Therfore either:
a) internal pointer must be mutable.
OR
b) copy constructor must take non-const argument.

4. Author chooses b).

5. But choosing (b) means that non-const auto_ptr can be copied
but const auto_ptr _cannot_ be copied.

6. Author want's to enable copying of const auto_ptr also.

7. Therefore he provides a conversion from auto_ptr to auto_ptr_ref.

8. He also provides constructor taking auto_ptr_ref as argument.

9. (7) and (8) enable const auto_ptr to be copied (after automatic
conversion to auto_ptr_ref).

That is my understanding.

Now in addition, I don't understand the following:-

A) Why is conversion operator non-const. It should be const
otherwise it won't work.

B) Why not just use a dummy variable as I outlined in the previous
post?

Sorry if I'm misunderstanding something.

Regards,
S.K.Mody.
回复
J2eeLearner 2003-01-13
"本来别人就是想让const auto_ptr不要交出所有权,可以你还要这么做,当然出错了。 "

我的那段程序,我用vc 6.0. devc 4.0都编译过了,不带auto_ptr_ref,那个对const auto_ptr的拷贝不能完成

devc4.9.70,它的头文件包含可能有点不同,已经把memory包含进来了,所以需要把我的auto_ptr改名字!

不过这些结果都是 编译错误,无法拷贝const auto_ptr!


// 如果有解释,估计也只能是 编译器不行的缘故了! 现在目前来看,还是可以不需要auto_ptr_ref,就可以阻止拷贝const auto_ptr的!
回复
earthharp 2003-01-13
呵呵,没看清楚我的回复。
const auto_ptr<T>不能用在copy ctor中, 是在这里决定的:
auto_ptr(auto_ptr& __a) : _M_ptr(__a.release()) {}

但是这样就不能让auto_ptr 从一个temporary object生成。象下面的:
auto_ptr<Helper> p4(auto_ptr<Helper>()); // Here

如果去掉了auto_ptr_ref
这里是不能成功的。
回复
earthharp 2003-01-13
template<class _Ty>
struct auto_ptr_ref
{ // proxy reference for auto_ptr copying
auto_ptr_ref(auto_ptr<_Ty>& _Right)
: _Ref(_Right)
{ // construct from compatible auto_ptr
}

auto_ptr<_Ty>& _Ref; // reference to constructor argument
};

auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()
: _Myptr(_Right._Ref.release())
{ // construct by assuming pointer from _Right auto_ptr_ref
}
回复
earthharp 2003-01-13
临时对象为一r value,
在这里通过auto_ptr_ref的帮助而使这种做法成功。
回复
earthharp 2003-01-13
我前段时间问过这个问题。
http://expert.csdn.net/Expert/topic/1164/1164249.xml?temp=.2167627
结果帖子好象被删了:O
我记得还提交了faq呢:D

你这里当然是错误的。
本来别人就是想让const auto_ptr不要交出所有权,可以你还要这么做,当然出错了。

auto_ptr_ref<T>是在下面的情况下起作用。
int main()
{

auto_ptr<Helper> p1(new Helper);
(*p1).say();
auto_ptr<Helper> p2(p1);
(*p2).say();

const auto_ptr<Helper> p3(new Helper);
auto_ptr<Helper> p4(auto_ptr<Helper>()); // Here

(*p3).say();
cin.get();
}
回复
发动态
发帖子
工具平台和程序库
创建于2007-09-28

2.4w+

社区成员

C/C++ 工具平台和程序库
申请成为版主
社区公告
暂无公告