sizeof和auto_ptr

sizeof 定义在<cstddef> header,主要使用方式可以是
1. sizeof type_name
2. sizeof object
3. sizeof (object) 其中2,3情况是一样的。
如果sizeof object的object是一个引用的化,得到的结果将是整个对象的大小,比如
int a[14];sizeof a = 14*4 = 56,如果object是其他情况,那么就仅仅是指当前对象的大小,注意,对象也包括指针,一般指针大小都是4。
这些都是非常普通的问题,这里我们讨论以下两点:
string str1;
string str2("yangshiquan");
string str3("chongqing");
cout << sizeof(string) << ‘\n’ << sizeof(str1) << ‘\n’ << sizeof(str2) << ‘\n’
<< sizeof(str3) << ‘\n’
结果将输出
16
16
16
16
刚看到结果时候我非常惊讶,细细一想。string是类,sizeof统计的不再是简单的内存计算,而是string类中的所有变量所需要分配内存的大小。sizeof(string)中的string本身也是call default constructor,所以四个一样不足为奇,但是为什么是16呢?
string source code中
typedef basic_string<char, char_traits<char>, allocator<char> > string;
继续追踪:
template<class _E,
 class _Tr = char_traits<_E>,
 class _A = allocator<_E> >
 class basic_string {…}
该模板类中如下定义了变量:
static const size_type npos;
_A allocator;
_E *_Ptr;
size_type _Len, _Res;
5?!那么大小应该是20才对,为什么是16呢?ok,static变量是不能算作对象变量的,所以pos为所有string对象维持了一个变量,也就是说,pos不为任何类对象所有,当然,在计算类所分配的空间大小的时候,pos的内存分配不计算在内,所以结果是16。npos是用于重新赋值assign的。
auto_ptr只能用于单个对象指针,但是不能用于数组,所有很多时候这个用起来并不方便,而且微软的auto_ptr并未实现reset方法,也就是在定义的时候就必须赋值。
我们感兴趣的是当两个auto_ptr指向同一个对象的时候,谁负责释放?这里采用了一个很有技巧性的方法,就是所有权,比如
auto_ptr<int> t(new int(2));t拥有该int对象的所有权,t负责释放他。
接下来我们使用t,编译器会自动在不需要t的时候free memory。
如果我们这样了,auto_ptr<int> t1 = t;显然,t和t1不能同时去free同一个对象,那么在auto_ptr底层实现的时候,t所指对象的所有权从t移到了t1,所以现在t1将负责free这个对象,而t则不再过问。这个实现非常巧妙。
另外,在指针赋值的时候,如果你写t1(t.get());那么程序就会出现不可知的问题,因为get函数简单返回底层真正的指针,而没有交出指针的所有权,
_Ty *get() const _THROW0()
{return (_Ptr); }

这时候t和t1就同时拥有了对象的所有权,你想象看,两个人拥有同一个老婆是什么后果?
所以如果想实现指针赋值,那么需要使用
t1(t.release());
_Ty *release() const _THROW0()
{((auto_ptr<_Ty> *)this)->_Owns = false;
return (_Ptr); }

我们可以看到release释放了t对该对象的所有权,所有所有权已经发生转移到t1,不会出现问题。
这里使用所有权的方式和我以前坚持的一个原则似乎有点类似。那就是,任何函数绝对不释放不是自己范围内定义的指针,不管中途你如何使用了指针,甚至给该指针重新分配空间。这点对于动态数组还是有用的,因为auto_ptr并不能管理数组内存。
另外一个让人高兴的是,auto_ptr,并不会降低程序的效率,因为本质上auto_ptr并未执行类似GC(garbage collection)的检查,只是做了本来该有你自己必须做的工作。比如
class T
{
public:
 T():count(NULL) {
  arr = new int[10];
  for (register i = 0; i < 10; i++ )
  {
   arr[i] = 0;
  }
 }
 ~T(){
  delete [] arr;
 }
 enum te{abl};
 static int g;
protected:
 size_t t;
private:
 int *count;
 int *arr;
};
auto_ptr<T> p1(new T());
p1只是简单的调用T的destructor函数,也就是说如果类的destructor函数没有显示释放你自己释放的内存,那么auto_ptr也无能为力。很多时候,auto_ptr并没有显著的作用,所有还是需要自己管理内存

此条目发表在C++分类目录。将固定链接加入收藏夹。

留下评论