定义自己的operator new和operator delete时注意点
2016-05-29 21:50
288 查看
前两天自己在写一个内存管理工具的时候,不知道怎么着手,想起了C++Primer里有个内存管理的例子CacheObject,虽然这个例子有点问题(内存泄露了),但作为一个起步者,还算一个很好的例子。重新复习了一下,发觉里面有几点需要注意:
第一、operator new和operator delete声明:
[html] view
plain copy
void* operator new(size_t)
[html] view
plain copy
void* operator new[](size_t)
[html] view
plain copy
void operator delete(void*)
[html] view
plain copy
void operator delete[](void*)
重定义操作符时,操作符的参数很多都与操作符的操作数直接关联,例如operator+:
[html] view
plain copy
Type operator+(const Type& lhs, const Type& rhs);
它的参数类型分别是operator +左和右两边的两个操作数类型。但是operator new的参数很特殊,是一个size_t类型,一个范围大小类型,而不是往常的操作数类型。从我的角度来理解,operator new作为一个内存开辟者,主要是为程序员开辟多少内存,所以开辟它不需要知道操作数的类型,只要知道操作数的大小便行了。
第二、operator new和operator delete作为成员函数,它是个静态函数
这里我先把CacheObject的代码贴出来
[cpp] view
plain copy
#ifndef CHACHEOBJECT_H
#define CHACHEOBJECT_H
#include <allocators>
//#include <memory>
#include <exception>
template<typename T>
class CacheObject
{
public:
void* operator new(std::size_t);
void operator delete(void *);
protected:
T* next; // 用于指向下一个未使用的内存
private:
static void add_to_freelist(T* p); // 回收内存到未分配列表
static std::allocator<T> alloc_mem; // allocator类型
static T* free_pointer; // 指向当前未分配
static const std::size_t chunk = 50; // 每一次开辟的内存数 50 * sizeof(T)
};
template<typename T> std::allocator<T> CacheObject<T>::alloc_mem;
template<typename T> T* CacheObject<T>::free_pointer = 0;
template<typename T>
void CacheObject<T>::add_to_freelist(T* p)
{
p->CacheObject<T>::next = free_pointer;
free_pointer = p;
}
template<typename T>
void* CacheObject<T>::operator new(std::size_t n)
{
if(sizeof(T) != n)
{
throw std::runtime_error("Type's size isn't match with CacheObject's size");
}
if(!free_pointer)
{
T* new_mem = static_cast<T*>(alloc_mem.allocate(chunk));
for(std::size_t i = 0; i < chunk; ++i)
add_to_freelist(&new_mem[i]);
}
this->chunk;
T* p = free_pointer;
free_pointer = free_pointer->CacheObject<T>::next;
return p;
}
template<typename T>
void CacheObject<T>::operator delete(void *p)
{
if(p)
add_to_freelist(static_cast<T*>(p));
}
#endif
在这一句里
[cpp] view
plain copy
static void add_to_freelist(T* p); // 把一个T类型的大小返回给内存未分配列表
一开始,我原先并没有static声明,即
[cpp] view
plain copy
void add_to_freelist(T* p); // 把一个T类型的大小返回给内存未分配列表
毕竟觉得free_pointer是一个静态成员变量,在add_to_freelist函数里负责指向未分配的内存,对于每个CacheObject对象调用add_to_freelist,都能使free_pointer如期的工作。好吧,那接下来就是编译:
“CacheObject<T>::add_to_freelist”: 非静态成员函数的非法调用
这就是vs给的结果,这个结果指向的是operator new函数里的add_to_freelist这一样
[cpp] view
plain copy
if(!free_pointer)
{
T* new_mem = static_cast<T*>(alloc_mem.allocate(chunk));
for(std::size_t i = 0; i < chunk; ++i)
add_to_freelist(&new_mem[i]);
}
“非静态成员函数的非法调用”意思就是说,非静态成员函数被当做静态成员函数来调用而导致非法出错。一开始我觉得很奇怪,在operator new这个函数里,我没有把它声明为静态,add_to_freelist又是普通的成员函数,难道成员函数调用成员函数有错?
我到网上找了很久都没有比较好的答案。后来,我放开书本,参考了源码,发现add_to_freelist的声明中C++primer的作者把其声明static函数。按着书本那样,我也加上了static声明,编译便通过了!!
为什么声明为static就可以通过,而非静态函数则不可通过?上面说了当前的错误是“非静态成员函数被当做静态成员函数来调用而导致非法出错”,那么就我当前知道的就有两种可能:1、非静态add_to_freelist在类作用域外被作用域操作符(::)所引用,明显,当前情况不是;2、非静态add_to_freelist函数无法在operator new里无法被识别,无法识别的最大原因是operator new是静态函数,它缺少this指针。为了印证我的想法,我做下面的变化:
[cpp] view
plain copy
if(!free_pointer)
{
T* new_mem = static_cast<T*>(alloc_mem.allocate(chunk));
for(std::size_t i = 0; i < chunk; ++i)
this->add_to_freelist(&new_mem[i]);
}
在非静态add_to_freelist前加上一个this,编译便出结果了:
“this”: 只能在非静态成员函数的内部引用
我在operator delete也做了同样地测试,结果和以上的结果一样。
结论:operator new和operator delete是静态
反思,为啥这两个操作符是默认静态的?
从我们平时的代码来思考
[cpp] view
plain copy
Type *t = new t;
delete t;
如果operator new不是静态的,那么上面new的写法也就是非法:对象还未创建而调用非静态函数。静态成员数据是与类关联的,并不与类对象关联,在程序开始便存在了,正因为这个,使得operator new可以在任何地方调用。从这个角度来看,体现了operator new的静态设计的合理性。
转自:http://blog.csdn.net/atlanticevix/article/details/6624490
第一、operator new和operator delete声明:
[html] view
plain copy
void* operator new(size_t)
[html] view
plain copy
void* operator new[](size_t)
[html] view
plain copy
void operator delete(void*)
[html] view
plain copy
void operator delete[](void*)
重定义操作符时,操作符的参数很多都与操作符的操作数直接关联,例如operator+:
[html] view
plain copy
Type operator+(const Type& lhs, const Type& rhs);
它的参数类型分别是operator +左和右两边的两个操作数类型。但是operator new的参数很特殊,是一个size_t类型,一个范围大小类型,而不是往常的操作数类型。从我的角度来理解,operator new作为一个内存开辟者,主要是为程序员开辟多少内存,所以开辟它不需要知道操作数的类型,只要知道操作数的大小便行了。
第二、operator new和operator delete作为成员函数,它是个静态函数
这里我先把CacheObject的代码贴出来
[cpp] view
plain copy
#ifndef CHACHEOBJECT_H
#define CHACHEOBJECT_H
#include <allocators>
//#include <memory>
#include <exception>
template<typename T>
class CacheObject
{
public:
void* operator new(std::size_t);
void operator delete(void *);
protected:
T* next; // 用于指向下一个未使用的内存
private:
static void add_to_freelist(T* p); // 回收内存到未分配列表
static std::allocator<T> alloc_mem; // allocator类型
static T* free_pointer; // 指向当前未分配
static const std::size_t chunk = 50; // 每一次开辟的内存数 50 * sizeof(T)
};
template<typename T> std::allocator<T> CacheObject<T>::alloc_mem;
template<typename T> T* CacheObject<T>::free_pointer = 0;
template<typename T>
void CacheObject<T>::add_to_freelist(T* p)
{
p->CacheObject<T>::next = free_pointer;
free_pointer = p;
}
template<typename T>
void* CacheObject<T>::operator new(std::size_t n)
{
if(sizeof(T) != n)
{
throw std::runtime_error("Type's size isn't match with CacheObject's size");
}
if(!free_pointer)
{
T* new_mem = static_cast<T*>(alloc_mem.allocate(chunk));
for(std::size_t i = 0; i < chunk; ++i)
add_to_freelist(&new_mem[i]);
}
this->chunk;
T* p = free_pointer;
free_pointer = free_pointer->CacheObject<T>::next;
return p;
}
template<typename T>
void CacheObject<T>::operator delete(void *p)
{
if(p)
add_to_freelist(static_cast<T*>(p));
}
#endif
在这一句里
[cpp] view
plain copy
static void add_to_freelist(T* p); // 把一个T类型的大小返回给内存未分配列表
一开始,我原先并没有static声明,即
[cpp] view
plain copy
void add_to_freelist(T* p); // 把一个T类型的大小返回给内存未分配列表
毕竟觉得free_pointer是一个静态成员变量,在add_to_freelist函数里负责指向未分配的内存,对于每个CacheObject对象调用add_to_freelist,都能使free_pointer如期的工作。好吧,那接下来就是编译:
“CacheObject<T>::add_to_freelist”: 非静态成员函数的非法调用
这就是vs给的结果,这个结果指向的是operator new函数里的add_to_freelist这一样
[cpp] view
plain copy
if(!free_pointer)
{
T* new_mem = static_cast<T*>(alloc_mem.allocate(chunk));
for(std::size_t i = 0; i < chunk; ++i)
add_to_freelist(&new_mem[i]);
}
“非静态成员函数的非法调用”意思就是说,非静态成员函数被当做静态成员函数来调用而导致非法出错。一开始我觉得很奇怪,在operator new这个函数里,我没有把它声明为静态,add_to_freelist又是普通的成员函数,难道成员函数调用成员函数有错?
我到网上找了很久都没有比较好的答案。后来,我放开书本,参考了源码,发现add_to_freelist的声明中C++primer的作者把其声明static函数。按着书本那样,我也加上了static声明,编译便通过了!!
为什么声明为static就可以通过,而非静态函数则不可通过?上面说了当前的错误是“非静态成员函数被当做静态成员函数来调用而导致非法出错”,那么就我当前知道的就有两种可能:1、非静态add_to_freelist在类作用域外被作用域操作符(::)所引用,明显,当前情况不是;2、非静态add_to_freelist函数无法在operator new里无法被识别,无法识别的最大原因是operator new是静态函数,它缺少this指针。为了印证我的想法,我做下面的变化:
[cpp] view
plain copy
if(!free_pointer)
{
T* new_mem = static_cast<T*>(alloc_mem.allocate(chunk));
for(std::size_t i = 0; i < chunk; ++i)
this->add_to_freelist(&new_mem[i]);
}
在非静态add_to_freelist前加上一个this,编译便出结果了:
“this”: 只能在非静态成员函数的内部引用
我在operator delete也做了同样地测试,结果和以上的结果一样。
结论:operator new和operator delete是静态
反思,为啥这两个操作符是默认静态的?
从我们平时的代码来思考
[cpp] view
plain copy
Type *t = new t;
delete t;
如果operator new不是静态的,那么上面new的写法也就是非法:对象还未创建而调用非静态函数。静态成员数据是与类关联的,并不与类对象关联,在程序开始便存在了,正因为这个,使得operator new可以在任何地方调用。从这个角度来看,体现了operator new的静态设计的合理性。
转自:http://blog.csdn.net/atlanticevix/article/details/6624490
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性