关于析构函数的显示调用
对于静态分配包含动态分配的资源并在析构函数中释放的对象是不可以显示调用析构函数的。原因在于,系统会在显示调用后作用域清理的时候再次调用析构函数,造成两次调用,从而释放两次资源,产生错误。对于没有在析构函数中释放资源的class,我做过测试,似乎没有什么坏的影响。
那么什么时候要显示调用呢?在对象本身就是使用动态分配的情况下需要显示调用以便释放这个资源的动态资源。我编写的一个memory管理程序就有这个需求。代码如下:
/*
************************************************************************
* This is a memory management class for the reason of c++ being weak
* in small object allocating and deallocating operations
* Author : Stephen Du
* Date : 07-9-13
*
*
************************************************************************
*/
#include
#include
#include
#include "newtrace.h"
namespace memory
{
/*
* The basic memory cell container which contains block_num_ blocks
*/
class chunk
{
private:
friend class fixedAllocator; // only fixedAllocator can operate chunk
//friend class smallObjAllocator;
bool reset(std::size_t block_size, unsigned int num_of_blocks){
assert(block_size > 0);
assert(num_of_blocks > 0);
assert(p_mem_ != NULL);
unsigned char* p = p_mem_;
for(unsigned int i = 0; i != num_of_blocks + 1;){
*p = ++i;
cout<<"In chunk reset"<<"block size "<printf("i is %d", *p);
p = p + block_size;
}
first_available_ = 0;
block_available_ = num_of_blocks;
return true;
}
bool is_full(void)const{
return (block_available_ == 0);
}
bool init(std::size_t block_size, unsigned int num_of_blocks){
assert(block_size > 0 && num_of_blocks > 0);
assert((block_size*num_of_blocks)/block_size == num_of_blocks);
// in case block_size or num_of_blocks are not int
p_mem_ = static_cast(::operator new(block_size * num_of_blocks));
assert(p_mem_ != NULL);
reset(block_size, num_of_blocks);
// *p_mem_ = 120;
// printf("in reset %d\n", *p_mem_);
return true;
}
bool release(void){
puts("memory released in chunk-----------------------------------------");
assert(p_mem_ != NULL && 1);
DEL(p_mem_);
p_mem_ = NULL;
return true;
}
void* allocate(std::size_t block_size){
// here in chunk domain I won't allow size are not
// the int * block_size_, in fixed it's allowed
assert(block_size > 0 && (first_available_*block_size)/block_size == first_available_ && is_full() != true);
// first_available_ = 1;
unsigned char* pchar = static_cast(p_mem_ + first_available_ * block_size );
first_available_ = *pchar;
--block_available_;
printf("In chunk allocated pchar is %p\n", pchar);
return pchar;
}
bool deallocate(void* p, std::size_t block_size){
unsigned char* px = static_cast(p);
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxx In chunk deallocate p is %p px is %p p_mem_ is %p\n", p, px, p_mem_);
assert(px >= p_mem_);
assert(block_size > 0);
assert((px - p_mem_)%block_size == 0);
unsigned char index = static_cast((px - p_mem_)/block_size);
*px = first_available_;
first_available_ = index;
++block_available_;
return true;
}
bool contain_me(void* p, std::size_t block_size, std::size_t num_of_blocks)const{
unsigned char* px = static_cast(p);
printf("In chunk contain_me p is %p px is %p p_mem_ is %p\n", p, px, p_mem_);
assert(px != NULL && block_size > 0 && num_of_blocks > 0);
return (px >= p_mem_ && p <= p_mem_ + block_size * num_of_blocks);
}
bool all_available(unsigned char num_of_blocks)const{
assert(p_mem_ != NULL);
return(block_available_ == num_of_blocks);
}
unsigned char get_block_available(void)const{ return block_available_; }
unsigned char* p_mem_;
unsigned char first_available_;
unsigned char block_available_;
};
/*
* fixedAllocator is used for managing the memory chunks so that be more convinience;In it we call a chunk page
*/
class fixedAllocator
{
public:
fixedAllocator():block_size_(0),
num_blocks_(0),
chunks_(0),
alloc_chunk_(NULL),
dealloc_chunk_(NULL),
empty_chunk_(NULL){}
~fixedAllocator(){
for(iter it(chunks_.begin()); it != chunks_.end(); it++){
it->release();
}
}
std::size_t count_empty(void)const{
//std::size_t count = 0;
return (NULL == empty_chunk_? 0 : 1);
}
bool init(std::size_t block_size, std::size_t page_size){
// cout<<"qqqqqqqqqqqqqq"< assert(block_size > 0 && page_size >= block_size);
std::size_t index = (page_size -1 + block_size) / block_size;
//cout<<"In chunk init index"< if(index > max_per_chunk_)
index = max_per_chunk_;
if(index < min_per_chunk_)
index = min_per_chunk_;
//cout<<"In chunk init index"< num_blocks_ = static_cast(index);
block_size_ = block_size;
//cout<<"In chunk num_blocks_"< assert(block_size_ == block_size);
}
/*
* The fist allocate request leads to get memory with add_chunk and make a
* lloc_chunk_ and dealooc_chunk_ to be correspond value
*/
void* allocate(void){
assert(NULL == empty_chunk_ || empty_chunk_->all_available(num_blocks_));
//empty_chunk_ never part allocated and other not but empty or full
assert(count_empty() < 2);
//at most only less than two empty exists;it's a rule
if(NULL == alloc_chunk_ || alloc_chunk_->is_full()){
//we need to add chunk in this case
if(NULL != empty_chunk_){
//get empty chunk from empty_chunk_
alloc_chunk_ = empty_chunk_;
empty_chunk_ = NULL;
}
else{ //get empty chunk from add_chunk
for(iter it(chunks_.begin()); ; it++){
if(it == chunks_.end()){
if(!add_chunk()){
//In add chunk the alloc_chunk_ will point to the right place
return NULL;
}
break;
}
if(!it->is_full()){
alloc_chunk_ = &*it;
break;
}
}
}
}
else if(alloc_chunk_ == empty_chunk_)
//check to modify the pointers for later use
empty_chunk_ = NULL;
assert(empty_chunk_ == NULL);
//empty_chunk_ must be null because we won't add_chunk if non-null
assert(alloc_chunk_ != NULL);
assert(!alloc_chunk_->is_full());
void* p = alloc_chunk_->allocate(block_size_);
assert(NULL != p);
return p;
}
bool deallocate(void*p , chunk* ck){
//printf("In fixedAllocator deallocate p is %p\n", p);
assert(!chunks_.empty());
assert(&chunks_.front() <= dealloc_chunk_);
assert(&chunks_.back() >= dealloc_chunk_);
assert(&chunks_.back() >= alloc_chunk_);
assert(&chunks_.front() <= alloc_chunk_);
assert(count_empty() < 2);
if(NULL == ck){
return false;
}
//assert(ck->get_block_available() == block_size_ * num_blocks_);
assert(ck->contain_me(p, block_size_, num_blocks_));
dealloc_chunk_ = ck;
//do_deallocate(ck);
assert(dealloc_chunk_ != empty_chunk_);
//if only one chunk int chunks_ delloc_chunk_ and alloc_chunk_
//are non-NULL and empty_chunk_ is NULL
assert(!dealloc_chunk_->all_available(num_blocks_));
assert(NULL == empty_chunk_ || (empty_chunk_->all_available(num_blocks_)));
dealloc_chunk_->deallocate(p, block_size_);
printf("In fixedAllocator deallocate p is %p\n", p);
if(dealloc_chunk_->all_available(num_blocks_)){
assert(empty_chunk_ != dealloc_chunk_);
if(empty_chunk_ != NULL){
chunk* last = &chunks_.back();
if(last == dealloc_chunk_){
dealloc_chunk_ = empty_chunk_;
}else if(last != empty_chunk_){
std::swap(*empty_chunk_, *last);
assert(last->all_available(num_blocks_));
last->release();
chunks_.pop_back();
if(alloc_chunk_ == last || alloc_chunk_->is_full())
alloc_chunk_ = dealloc_chunk_;
}
}
empty_chunk_ = dealloc_chunk_;
}
assert(count_empty() < 2);
return true;
}
inline std::size_t get_block_size()const{ return block_size_; }
const chunk* contain_me(void*p)const;
typedef std::vector chunks;
typedef chunks::iterator iter;
typedef chunks::const_iterator const_iter;
private:
fixedAllocator(const fixedAllocator& f){}
bool add_chunk(void){
bool allocated = false;
std::size_t size = chunks_.size();
if(size == chunks_.capacity()){
if(size == 0)
size = 4;
chunks_.reserve(size * 2);
}
chunk ck;
cout<<"In add chunk"< allocated = ck.init(block_size_, num_blocks_);
if(allocated)
chunks_.push_back(ck);
alloc_chunk_ = &chunks_.back();
dealloc_chunk_ = &chunks_.front();
return true;
}
// bool release(void);
static unsigned char max_per_chunk_;
static unsigned char min_per_chunk_;
std::size_t block_size_;
unsigned int num_blocks_;
chunks chunks_;
chunk* alloc_chunk_;
chunk* dealloc_chunk_;
chunk* empty_chunk_;
};
unsigned char memory::fixedAllocator::max_per_chunk_ = UCHAR_MAX;
unsigned char memory::fixedAllocator::min_per_chunk_ = 8;
const chunk* fixedAllocator::contain_me(void* p)const
{
if(p == NULL)
return NULL;
printf("In fixedAllocator contain_me p is %p block_size %d num_blocks_ is %d\n", p, block_size_, num_blocks_);
const_iter ii = chunks_.begin();
for(; ii != chunks_.end(); ii++){
if((ii->contain_me(p, block_size_, num_blocks_)) == true)
break;
}
if(ii != chunks_.end()){
const chunk& ck = *ii;
return &ck;
}
return NULL;
}
//bool fixedAllocator::release(void)
//{
//
//}
/*
* This class allows dynamic size aollocating request and are
* used by the basic type as cStr cValue and so on by my project
*/
#define DEFAULT_MAX_OBJ_SIZE 256 // 16 block_size_
#define DEFAULT_ALIGN 16 // a block_size_
#define DEFAULT_PAGE_SIZE 1024
class smallObjAllocator{
public:
smallObjAllocator(std::size_t page_size, std::size_t max_obj_size, std::size_t algin);
// page_size is the total of a chunk
~smallObjAllocator();
void* allocate(std::size_t s);
bool deallocate(void* p);
bool deallocate(void* p , std::size_t s);
inline std::size_t get_max_size(void)const { return max_obj_size_; }
inline std::size_t get_align(void)const { return align_; }
private:
smallObjAllocator();
// smallObjAllocator(smallObjAllocator&);
// smallObjAllocator& operator= (smallObjAllocator&);
fixedAllocator* alloc_pool_;
std::size_t max_obj_size_;
std::size_t align_;
};
//std::size_t smallObjAllocator::max_obj_size_ = DEFAULT_MAX_OBJ_SIZE;
//std::size_t smallObjAllocator::align_ = DEFAULT_ALIGN;
smallObjAllocator::smallObjAllocator(void):max_obj_size_(DEFAULT_MAX_OBJ_SIZE),
align_(DEFAULT_ALIGN)
{
int num_of_objs = (DEFAULT_MAX_OBJ_SIZE + DEFAULT_ALIGN-1) / DEFAULT_ALIGN;
alloc_pool_ = NEW_ARRAY_EXT(0) fixedAllocator[num_of_objs];
for(int i = 0; i < num_of_objs; i++){
alloc_pool_[i].init((i+1)*DEFAULT_ALIGN, DEFAULT_PAGE_SIZE);
}
}
//smallObjAllocator::smallObjAllocator(const smallObjAllocator& soa){
// alloc_pool_ = static_cast(NEW fixedAllocator[((soa.max_obj_size_+1) / soa.align_)]);
smallObjAllocator::smallObjAllocator(std::size_t page_size,
std::size_t max_obj_size,
std::size_t align):max_obj_size_(max_obj_size),
align_(align)
{
int num_of_objs = (max_obj_size - 1 + align) / align;
//This leads to page_size>=2*max_obj_size
alloc_pool_ = NEW_ARRAY_EXT(0) fixedAllocator[num_of_objs];
for(int i = 0; i < num_of_objs; i++)
alloc_pool_[i].init((i+1)*align, page_size);
}
smallObjAllocator::~smallObjAllocator(void)
{
int num_of_objs = (max_obj_size_ - 1 + align_) / align_;
for(int i = 0; i < num_of_objs; i++)
alloc_pool_[i].~fixedAllocator();
}
//{ DEL_ARRAY(alloc_pool_); alloc_pool_ = NULL; }
//the destruct of fixedAllocator will recursively free the memory
void* smallObjAllocator::allocate(std::size_t s)
{
if(s > get_max_size())
//If all the alloc_pool_ member can't fit for "s" just directly new
return direct_new(s);
assert(alloc_pool_ != NULL);
if(s == 0)
s = 1;
std::size_t index = (s+get_align()-1) / get_align() - 1;
std::size_t max_index = (get_max_size()+get_align()-1) / get_align() - 1;
cout<<"max_index is "< assert(index <= max_index);
fixedAllocator& alloc = alloc_pool_[index];
assert(alloc.get_block_size() >= s);
cout<<"In smallObjAllocator allcoate"<// assert(alloc.get);
void* p = alloc.allocate();
printf("In smallObjAllocate allocate p is %p\n ", p);
if(alloc_pool_[index].contain_me(p))
puts("p0 in index 0!!!!!!!");
else
puts("p0 not index 0!!!!!!!!");
if(!p)
throw std::bad_alloc();
return p;
}
bool smallObjAllocator::deallocate(void* p)
{ //I need to find where is p in
if(p == NULL)
return false;
int num_of_jobs = (max_obj_size_ - 1 + align_) / align_;
chunk* p_ck = NULL;
int i = 0;
for(; i < num_of_jobs; i++){
p_ck = const_cast(alloc_pool_[i].contain_me(p));
if(p_ck != NULL){
cout<<"p_ck non-NULL"<printf("p is %p\n", p);
break;
}
}
cout<<"The alloc_pool_ i is "< fixedAllocator* temp = &(alloc_pool_[i]);
if(p_ck == NULL){ //p is by newed not fixedAllocator
printf("operator delete in dealocate! p is %p\n", p);
::operator delete(p); //consider it as raw memory and
//release the memory it holds
bool smallObjAllocator::deallocate(void* p, std::size_t s)
{
if(p == NULL)
return false;
int index = (s + align_ -1) / align_ - 1;
int max_index = (max_obj_size_ + align_ -1) / align_ - 1;
if(index > max_index){ // p is newed not by fixedAllcator
::operator delete(p);
return true;
}
//assert(alloc_pool_[index] != NULL);
chunk* ck = const_cast(alloc_pool_[index].contain_me(p));
assert(ck != NULL);
alloc_pool_[index].deallocate(p, ck);
p = NULL; //avoid raw pointer
return true;
}
/*
* This operator= is not so bad in need and it related to deep copy action so
* I stop here
*/
//smallObjAllocator& smallObjAllocator::operator= (const smallObjAllocator& soa){
// max_obj_size_ = soa.get_max_size();
// algin_ = soa.get_align();
//
//}
} // memory
以上程序的使用方法
针对c++默认的内存管理策略在遇到几个到几百字节的small object的时候,性能明显下降,我们需要自己处理这种情况
以便程序高效的运行(实际上几乎所有c++程序都是要这样做,至少对于string这种类型,它是必须的)
使用方法:
环境:linux/Windows(程序中使用到pthread_mutex_t类型windows只要换一下就行)
编译器:GNU gcc version 4.1.1(其他的不要太老也行)
在你的small object class内部定义一个private static 类型的成员,大致类似:
__MEMORY_TRACE__和_DEBUG宏用于开启new/delete的行为跟踪程序以及debug信息
#include “smallobjmanage.h”
class test{
public:
//以下接口用于操作test_pool_获得raw memory;如果需要可以自己static_cast成所需要的类型
void*allocate(std::size_t s){
void* p = test_pool_.allocate(s);
if(!p)
return NULL;
return p;
}
void deallocate(void*p, std::size_t s){、、用于释放类型大小已知的类型
assert(p !=NULL);
test_pool_.deallocate(p, s);//如果这里你定义成了指针一定记得显式调用~smallObjAllocato释放memory防止泄漏
//deallocate知识放弃内存使用权并没有释放内存!!!
}
void deallcate(void* p){ //用于释放不知道大小和类型的memory
assert(p !=NULL);
test_pool_.deallocate(p);
}
private:
static smallObjAllocator test_pool_;
};
//smallObjAllocator Test::test_pool_; //使用默认的构造函数page_size = 1024表示内存的页大小, max_obj_size_ = 256
//表示你希望这个内存管理器支持的最大object,
//align = 16表示最小内存单元(就是最小的object)
//以上参数必须满足:page_size >= 2* max_obj_size >= 2* align
smallObjAllocator Test::test_pool_(2048, 512, 32);
关于operator<<,operator>>重载
在class内部重载这个操作符必须返回otream&并且第一个参数也是这个引用,第二个参数是本class的引用,最重要的是如果在calss内部重载(外部不要)一定要把这个函数声明成friend类型(原因很明显,但对于新手就容易忘记)
class test{
public:
test(){ p = static_cast
(new char[20]); }
~test(){ cout<<"In ~test()"< bool print(int t){ cout<<"In the print function"<
friend ostream& operator<< (ostream& out, test& t){ out<friend istream& operator>> (istream& in , test& t){ in>>t.buf; return in; }
char* p;
private:
char buf[20];
};
int
main()
{
test tt;
cin>>tt;
cout<}
关于c++中的回调函数
c++程序很多的场合需要回调函数(就是在class的成员函数的内部调用一个函数的行为),如下是两个最简单的实例:
class test{
public:
test(){ p = static_cast(new char[20]); }
~test(){ cout<<"In ~test()"< bool print(int t){ cout<<"In the print function"< char* p;
};
template
static bool call_back(T& t, boost::function f)
{
typedef bool(*back)(int);
f(&t, 0);
f(&t ,1);
}
bool xyz(char* p)
{
cout<<"in xyz !!"<}
bool call_xyz(bool(*pp)(char*))
{
char buf [] = "stephen!";
char buf0 [] = "steven!";
pp(buf);
pp(buf0);
}
int
main()
{
test tt;
call_back(tt, &test::print);
call_xyz(&xyz);
}
STL库中multimap的使用注意事项
1.使用insert方法插入相同key的值
2.map与multimap的不同之处:
1)map的insert方法返回一个新插入的pair
2)multimap的insert返回一个iterator(执行一定可以)
equal_bound(k):查找以k相等的值,并返回一个pair类型
lower_bound(k):查找第一个与k关联的值
upper_bound(k):查找第一个大于k的值(通常key是string的情况下有一个比较的字典)
count(k) :计算有多少个k
find(k) :查找第一个符合k的迭代指针
关于const
C会对const类型的数据进行优化(默认),方法是采用常量折叠。就是将const的数值直接计算到需要使用的地方而并不分配内存!但是,如果我们使用指针指向常量,并修改它的内容呢?答案是编译器会为你的这种行为无奈的分配内存,但是在使用const变量名字引用的时候却不是内存的内容,依然故我的是你定义const的值,而通过指针引用却是另一个你使用指针修改的值!!
被const修饰的class member function必须使用const版本的iterator进行访问!!
关于类型转换后存储空间大小的认识
今天看了一个程序对一个unsigend char的字符执行转换成为unsigned int,我怀疑编译器是不是会增加原来的unsigend char的大小。试了一下果然由1bytes 变成了4 bytes。尽管这对别人可能是一个小时情,但是我以前还真的没有细致思考过来这种事情的结果。
关于throw的一些注意事项
直接throw会导致对象的copy操作(而且除了指针外都是两次哦!原因是防止对象是局部而释放掉)。
关于static class以及static function,global calss, global function in C++
对于这几种类型它们最大的特点就是没有C++中独有的this指针。置于原因我也是根据别人以及自己的使用经验来解释并没有什么权威的解释。下面就把我的理解写出来:
static类型相当于全局的类型而全局的变量,对象等等会在程序退出后自动回收资源,因此this的存在是多余的(无论是编译器还是程序员都不需要delete this的行为);
C++中const变量与直接使用macro #define的区别
我们知道macro定义的变量会在预处理的时候进替换,而const变量也会通过自动优化的方式进行常量迭代,那么它们有什么区别?下面是我的总结:
1.使用macro定义的常量一定会替换成常量,而const方式,虽然优化的条件下行为与macro相同,但是不优化的情况下,const方式仍然是”变量“它可以分配内存,从而可以做macro方式不能做的事情(例如debug);
2.const方式是有类型的,而macro是没有的。
最后,class内部的常量必须在构造的时候初始化(构造函数内部初始化,一般使用初始化列表),此后不能改变。我们于可以使用enum类型代替const。
关于野指针的总结
在编写应用程序尤其是大型应用程序的时候,一定要避免野指针的出现,否则后果只有你自己痛苦!呵呵。首先了解一下野指针是什么吧。
我们知道在C/C++中是允许动态的分配内存并使用的,使用形式定义一个指针指向返回指向内存的指针(可能是raw的也可能调用了构造函数),此后使用完毕后再释放。很多人释放的时候,不是很注意将自己定义的指针指向NULL,这种指针就叫做野指针。野指针的坏处是:你可能还可以使用这个“野”的指针访问之前的memory,有人可能会问:不是已经释放掉了吗?怎么还是可以访问呢?答案是:编译器释放的时候只是将内存的使用管理权收回了,也就是这部分内存不属于任何人,但是别人如果很强,直接使用一个地址来访问这里可不可以呢?当然是可以的!也可以向里面写入自己的数据!问题是编译器很可能将里面的内容覆盖,这时候,你的数据就丢了。结果很正常,你要使用这块memory可以向编译器索取,偷偷摸摸的行为编译器自然不会理睬。
为了避免我们一时疏忽使用野指针产生的不确定行为,在释放内存后一定将自己的指针赋值NULL。
简单内存越界的例子
我么可能经常听说内存越界但是自己却从没有经历过,下面列举一个简单的例子:
char buf[3];
strcpy(buf, "Stephen Du is a good boy!");//注意这里我将一个26个字符的串copy进入只能容纳3个字符的数组中
cout<<"The content in buf is "< 以上程序可以正常编译、执行。??????????????已经越界了编译器也不管?实际上是这样的。这也是为什么大家都推荐使用strncpy而不是strcpy的原因。好了,其他越界的例子大家可以自己“造”一些,玩玩!
boos中function函数指针的使用
总结一下function函数指针的使用方法。
我们经常使用一个类似于
typedef int (*p_func)(int);
形式的函数指针做为回掉的方法。但是当在c++中存在大量的类型的时候,这种方法真的让人觉得很累。于是c++的boost库中提供了一个很方便的工具类function。
使用之前,需要包含boost::function.hpp并且将boost namespace声明好。
其实function是一个class template 使用前要将必要的类型参数传递给它:
function func;
上面声明了function class tempalte 的实例,这个实例对应于所有返回值是int类型,而有两个int类型参数的函数指针。
以上方法比较直观,但是对于有些编译器是不支持的以下是几个兼容性较好的替代。
function1 func1;返回值是int,有一个int参数的函数指针;
function2 func1;返回值是int,有int,float两个参数的函数指针;
function3 func1;返回值是void,有int,char,short三个参数的函数指针;
最多支持function100,因此使用应该已经够用了。
c/c++中获得指针指向的内存大小的方法
有很多的应用程序开发中需要知道从外部传入的指针指向的内存的大小。但是这个问题似乎有点不是很好处理,下面是我的处理方法。
const int size = 90;
int* p = new int[size];
void function(int* p)
{
需要知道p指向的内存区域的大小
}
方法1:
直接传入size的大小
void function(int* p, int size)
{
需要知道p指向的内存区域的大小
}
方法2:
使用malloc.h中的malloc_usable_size()(这是linux下的函数;Windows下是_msize())来获得。
显然方法2比较正统,但是不知道,这个函数调用开销是否比方法1大。个人感觉,方法1会更加高效一些;而方法2似乎不常用!
关于静态数据成员使用
class内部static类型数据成员,必须使用外部初始化(也不能使用成员列表的形式初始化),否则编译阶段会报一个undefine
variable的错误;
对于const static int类型的数据可以在内部直接初始化;静态数据成员也可以作为缺省参数传递给成员函数;针对需要被多次包含的头文件,如果包含了
拥有静态数据成员class那么需要将静态成员初始化部分的代码分离到其他不会被多次包含的文件,因为静态数据成员只能初始化一次!
关于singleton模式的使用补充说明
private指向自己的指针必须是静态,public中call construct的成员函数必须是static的,原因在于我们需要先定义一个指向NULL该类型的指针来call
public中的construct函数来构造自己而此时除了static成员之外我们是NULL的(static成员在class定义之前已经存在!),声明为static后,
public中的construct已经存在,不会产生编译错误!
关于template function的非类型参数
通常模板中我们使用“类型”参数来声明一个新的模板(function
or class)实例化的时候传入一个类型(自定义或者系统默认系统的类型)即可。
我现在提及的是“非类型”参数,就是说在模板声明的时候我们给一个实例参数,如下
template class test{
};
这样声明模板实例的时候传入一个整型就可以了:
test te;
关于成员函数指针的问题
C++中不能如C中那样简单定义一个返回值和参数一致的function pointer 指向class内部的function
typedef int(*fun)(void);
class test{
public:
int
xx(){}
};
fun p_fun;
p_func = &test::xx;//error!!!!!!!
原因在于指向class内部函数的指针还有一个重要的信息需要包含在内,那就是this指针而普通的指针是没有办法接受这个信息的。
正确的使用方法:
typedef int(test::*fun)();
fun p_fun = &test::xx;
另外:
int (test::*fun)() = 0;
fun = &test::xx;
也是可以的。
注意:static成员由于没有this指针因此操作的方法与一般指针没有差别!!!
这种指针可以应用于hook以及缺省参数的应用中
阅读(1509) | 评论(0) | 转发(0) |