关于STL的_Construct实现问题

描述:

stl(指vs2008的stl)中的vector在分配对象的时候,出现一些意想不到的事情.

比如:
class A
{};
vector<A> a(10);

这样就可以构造出一个有10个元素类型为A的vector, 考察其构造过程,就会发现其实并不是构造了10个A,而是构造了11个A,然后再析构1个.

这个主要是实现的问题,看源码就知道,

explicit vector(size_type _Count)
: _Mybase()
{ // construct from _Count * _Ty()
_Construct_n(_Count, _Ty());
}

void _Construct_n(size_type _Count, const _Ty& _Val)

因为_Construct_n在构造过程中要调用class A 的拷贝构造函数,所以第2个参数为一个_Ty类型,也就是上面的class A,的一个实例.

于是就先构造出一个临时的A,传给_Construct_n,构造函数完成后,析构掉.


感觉主要原因实现时偷懒了吧. 可以在Alloc里面增加一个使用 ::new(_p) _Ty() (默认构造函数)的函数就好了,为什么非要用 ::new(_p) _Ty(_Val) (拷贝构造函数)  呢.

 

同样的问题,就是在

 

vector<A> x(10);

vector<A> y = x;

 

这个时候y=x调用的是vector的拷贝构造函数,按照C++的"习惯",容器里面的对象也应该使用拷贝构造函数构造,但是不幸的是由于实现的时候是用copy(x.begin(), x.end(), y.begin()) 的,所以就全部用 operator=  来做了.

首先可以看到这是两个问题,第一个问题,我看了SGI STL和C++标准确实是这样实现的,并没有提供对默认构造函数的placement new。

C++ standard 20.4.1.1

void construct(pointer p, const_reference val);
Returns: new((void *)p) T(val)

 

但是C++标准描述的是DefaultAllocator,但是用户可以自己开发Allocator。那么问题就是C++标准为什么这样定义?

我觉得是因为性能,有人认为多了一次默认构造会造成性能下降,其实STL考虑的是给使用者Copy On Write的机会。如果STL容器中插入的是带有引用计数功能的对象。那么拷贝构造函数就会比构造一个新的对象快很多。因为对象内部的成员函数不需要进行分配内存和初始化,只是引用计数发生变化而已。CString就是这样实现的。具体参见More Effective C++或者 Exceptional C++ 和MSDN。

关于第二个问题,我觉得是为了保证强烈异常安全。

vector<A> x(10);

vector<A> y = x;

将拷贝构造分为两步

1 构造y中的对象,分配内存初始化。

2 用operator =进行赋值。

y分配内存失败就不进行下面的赋值。而operator =是可以保证异常安全的。

但是如果使用拷贝构造函数则不能保证上下文完整性。

高手们还有什么其他的意见可以讨论。

#3 0x000000000046ef07 in ~_Vector_base (this=0x6a4ead0, __in_chrg=<value optimized out>) at /usr/include/c++/4.4/bits/stl_vector.h:132 #4 0x000000000046dd2d in ~vector (this=0x6a4ead0, __in_chrg=<value optimized out>) at /usr/include/c++/4.4/bits/stl_vector.h:313 #5 0x000000000046b7c8 in ~ZXJC_LineCover (this=0x6a4ea30, __in_chrg=<value optimized out>) at ../../web/demonitordll/dbproc.h:236 #6 0x000000000046b7e2 in std::_Destroy<ZXJC_LineCover> (__pointer=0x6a4ea30) at /usr/include/c++/4.4/bits/stl_construct.h:83 #7 0x000000000046795a in std::_Destroy_aux<false>::__destroy<ZXJC_LineCover*> (__first=0x6a4ea30, __last=0x6a4ea18) at /usr/include/c++/4.4/bits/stl_construct.h:93 #8 0x000000000045bc7f in std::_Destroy<ZXJC_LineCover*> (__first=0x6a4e960, __last=0x6a4ea18) at /usr/include/c++/4.4/bits/stl_construct.h:116 #9 0x000000000044920f in std::_Destroy<ZXJC_LineCover*, ZXJC_LineCover> (__first=0x6a4e960, __last=0x6a4ea18) at /usr/include/c++/4.4/bits/stl_construct.h:142 #10 0x00007f3769464bde in std::vector<ZXJC_LineCover, std::allocator<ZXJC_LineCover> >::_M_insert_aux (this=0x7f374ee9aca0, __position=..., __x=...) at /usr/include/c++/4.4/bits/vector.tcc:359 #11 0x00007f376945c985 in std::vector<ZXJC_LineCover, std::allocator<ZXJC_LineCover> >::push_back (this=0x7f374ee9aca0, __x=...) at /usr/include/c++/4.4/bits/stl_vector.h:741 #12 0x00007f3769445ca0 in CDBProc::GetLineCoverageRate (this=0x7f3758003690, o_fStatistRate=@0x7f374ee9acdc, o_strErr=..., feederVec=...) at dbproc.cpp:3472
最新发布
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值