在对象定义的地方,编译器会插入对象的构造函数;在对象销毁的地方,编译器会插入对象的析构函数。传递给这两个函数的的第一个参数就是当前对象的this指针(隐藏起来了)。所以定义一个对象时,会先分配一块内存块,然后把这个内存块的基址传给构造函数,构造函数负责对这个内存块进行初始化。而在销毁一个对象之前,先把这个对象的基址传给析构函数,析构函数对这个内存块进行清理收尾的工作,然后才销毁这个对象(如出栈,逻辑上销毁了这个对象,但在物理内存中这个对象占用的空间还是存在的。把不再使用的空间置零是一个好的习惯。)。
不调用构造函数是无法真正完成构造一个对象的,不调用析构函数是无法销毁一个对象的(longjmp另作考虑),因为C++编译器做了手脚。比如:
class X
{
public:
X() {}
};
void func( int i )
{
if ( i < 10 )
{
goto lable1;
}
}
X obj1; // 这里可能被跳过,而在编译时这里就给分配了内存块,而现在这个内存块可能没被初始化(构造函数的定义就放在X obj1语句的后面,而它可能被跳过),所以对这样的写法,编译器会给出出错信息。
lable1:
....
同样对于这样的写法也是报错的:
switch( int n )
{
case 1:
X obj2; // 编译时就分配了空间,但可能构造函数给跳过而没有初始化,所以报错
break;
case 2:
X obj3; // 报错
break;
...
}
顺序数组的一个实现(可用作缓存):
/***
* 直接存储对象的数组 头文件
* bluesky
*/
#ifndef _DIRECTARRAY_H_
#define _DIRECTARRAY_H_
#include <cstdlib>
#include <string.h>
namespace _bs_classes_
{
const int INC_COUNT = 100;
class DirectArray
{
public:
DirectArray( int nElementSize );
virtual ~DirectArray( );
public:
// 增加一个元素
// 成功则返回这个元素的下标,否则返回-1
int AddElement( void * pNewElement );
// 取一个元素
// 成功则返回这个元素的地址,否则返回0
void * FetchElement( int nIndex );
// 取得数组元素的个数
int GetCount( );
// []操作
void * operator[]( int nIndex );
private:
// 增长数组
bool InflateArray( int nIncElementCount );
private:
int m_nElementSize; // 元素占用的字节数
int m_nCurrentQuantity; // 当前能容纳的元素个数
int m_nNextElementIndex; // 最后一个元素的下一个位置的下标
unsigned char * m_pArrayStartAddr; // 数组起始地址
};
}
#endif
/***
* 直接存储数组 实现文件
* bluesky
*/
#include "DirectArray.h"
#include <cassert>
namespace _bs_classes_
{
DirectArray::DirectArray( int nElementSize )
{
m_pArrayStartAddr = 0;
assert( nElementSize > 0 );
if ( nElementSize <= 0 )
return;
m_nElementSize = nElementSize;
m_nCurrentQuantity = 0;
m_nNextElementIndex = 0;
}
DirectArray::~DirectArray( )
{
if ( m_pArrayStartAddr )
{
free( m_pArrayStartAddr );
m_pArrayStartAddr = 0;
}
}
/ 对外接口 begin
int DirectArray::AddElement( void * pNewElement )
{
assert( pNewElement );
if ( !pNewElement )
return -1;
if ( m_nNextElementIndex >= m_nCurrentQuantity )
{
bool bIsInflateSuccessful = InflateArray( INC_COUNT );
if ( !bIsInflateSuccessful )
return -1;
}
memcpy( m_pArrayStartAddr + m_nNextElementIndex * m_nElementSize, pNewElement, m_nElementSize );
m_nNextElementIndex ++;
return m_nNextElementIndex - 1;
}
void * DirectArray::FetchElement( int nIndex )
{
assert( nIndex >= 0 && nIndex < m_nNextElementIndex );
if ( nIndex < 0 || nIndex >= m_nNextElementIndex )
return 0;
return m_pArrayStartAddr + nIndex * m_nElementSize;
}
void * DirectArray::operator[]( int nIndex )
{
return FetchElement( nIndex );
}
int DirectArray::GetCount( )
{
return m_nNextElementIndex;
}
/ 对外接口 end
内部函数 begin
bool DirectArray::InflateArray( int nIncElementCount )
{
assert( nIncElementCount > 0 );
if ( nIncElementCount <= 0 )
return false;
void * pNewMemoryStartAddr = (void *)realloc( m_pArrayStartAddr,
( m_nCurrentQuantity + nIncElementCount ) * m_nElementSize );
assert ( pNewMemoryStartAddr );
if ( pNewMemoryStartAddr == 0 )
return false;
m_pArrayStartAddr = (unsigned char *)pNewMemoryStartAddr;
m_nCurrentQuantity += nIncElementCount;
return true;
}
内部函数 end
}
/* 测试代码
* bs
*/
#include <iostream>
using namespace std;
#include "DirectArray.h"
using namespace _bs_classes_;
void testDirectArray( )
{
DirectArray intArray( sizeof(int) );
int aa = 10;
intArray.AddElement( &aa );
aa = 20;
intArray.AddElement( &aa );
int nSize = intArray.GetCount( );
for ( int nPos = 0; nPos < nSize; nPos ++ )
{
cout << *((int*)intArray[nPos]) << endl;
}
// 用作缓存
const int BUFFER_SIZE = 128;
char szBuffer[ BUFFER_SIZE ] = { 0 };
DirectArray stringStash( sizeof(char) * BUFFER_SIZE ); // 一个元素占BUFFER_SIZE个字节
FILE * pFile = fopen( "DirectArray.cpp", "r" );
if ( pFile != NULL )
{
while ( fgets( szBuffer, BUFFER_SIZE - 1, pFile ) )
{
stringStash.AddElement( (void*)szBuffer );
}
}
// print string in stringStash
for ( int nIndex = 0; nIndex < stringStash.GetCount(); nIndex ++ )
{
cout << (char *)stringStash[ nIndex ] << endl;
}
}
链式栈的一个实现(单链表实际上就可以作为栈,而不是让栈包含一个单链表):
/************************************************************************/
/* 栈 声明文件
/* bluesky
/************************************************************************/
#ifndef _BS_STACK_H
#define _BS_STACK_H
namespace _bs_stack
{
class Stack
{
private:
struct Element
{
void * m_pData; // point to real data
Element * m_pNext; // next pointer
void Initialize( void * pData, Element * pElement );
Element( void * pData, Element * pElement );
} *head;
int m_nSize; // element amount of stack
void (*m_pDestroy)( void * pData ); // 销毁实际数据的指针函数
public:
// 由于本结构是不考虑实际数据的类型和它的产生方式的,所以要记录下外界对实际数据的销毁函数的指针
// param destroy 销毁实际数据的指针函数
Stack(
void (*destroy)(void * pData)
);
~Stack( );
void ZeroInit( );
public:
void push( void * pData );
void * pop( );
void * peek( );
int size( ) { return m_nSize; }
};
}
#endif // _BS_STACK_H
/************************************************************************/
/* 栈 实现文件
/* bluesky
/************************************************************************/
#include "Stack.h"
using namespace _bs_stack;
#include <cassert>
#include <cstring>
#include <cstdlib>
void Stack::ZeroInit( )
{
head = 0;
m_nSize = 0;
m_pDestroy = 0;
}
Stack::Stack(
void (*destroy)(void * pData)
)
{
ZeroInit();
m_pDestroy = destroy;
}
Stack::~Stack( )
{
if ( m_nSize == 0 )
{
memset( (void*)this, 0, sizeof(Stack) );
return;
}
Element * pElementTemp = head;
while ( head )
{
pElementTemp = head->m_pNext;
void * pData = head->m_pData;
//free( pData ); // 不能一概用free,有可能是new出来的,由外界的接口来销毁是最合适的
m_pDestroy( pData );
free( head );
head = pElementTemp;
}
memset( (void*)this, 0, sizeof(Stack) );
}
// 对外接口 begin
void Stack::push(
void * pData
)
{
assert( pData != 0 );
if ( pData == 0 )
return;
Element * pNewElement = (Element *)malloc( sizeof(Element) );
assert( pNewElement );
pNewElement->Initialize( pData, head );
head = pNewElement;
m_nSize ++;
}
void * Stack::pop( )
{
if ( m_nSize == 0 )
return 0;
Element * pElementTemp = head;
head = head->m_pNext;
void * pRetData = pElementTemp->m_pData;
free( pElementTemp );
m_nSize --;
return pRetData; // 外界负责管理这个内存块
}
void * Stack::peek()
{
if ( m_nSize == 0 )
return 0;
return head->m_pData;
}
// 对外接口 end
// 内部结构 begin
Stack::Element::Element(
void * pData,
Element * pElement
)
{
m_pData = pData;
m_pNext = pElement;
}
void Stack::Element::Initialize(
void * pData,
Element * pElement
)
{
m_pData = pData;
m_pNext = pElement;
}
// 内部结构 end
/* 测试代码
* bluesky
*/
#include <iostream>
using namespace std;
#include <string>
#include <cstdlib>
#include <cassert>
#include "Stack.h"
using namespace _bs_stack;
void destroy( void * pData )
{
assert( pData );
if ( !pData )
return;
delete pData;
pData = 0;
}
void testStack1( )
{
Stack intStack( destroy );
int nPos = 0;
const int nLen = 10;
for ( nPos = 0; nPos < nLen; nPos ++ )
{
intStack.push( (void*)new int(nPos) );
}
int * pInt = 0;
while ( pInt = (int*)intStack.pop() )
{
cout << *pInt << endl;
delete pInt;
}
cout << "now stack size: " << intStack.size() << endl;
}
void destroy2( void * pData )
{
assert( pData );
if ( !pData )
{
return;
}
free( pData );
pData = 0;
}
void testStack2( )
{
Stack txtStack( destroy2 );
FILE * pFile = fopen( "Stack.h", "r" );
assert( pFile );
if ( !pFile )
{
cout << "open file error" << endl;
return;
}
const int bufferSize = 126;
char buf[ bufferSize ] = { 0 };
while ( fgets( buf, bufferSize, pFile ) )
{
void * pData = malloc( strlen( buf ) + 1 );
memset( pData, 0, strlen( buf ) + 1 );
strcpy( (char*)pData, buf );
txtStack.push( pData );
}
cout << "now stack size before pop: " << txtStack.size( ) << endl;
int nTimesLimit = 30;
void * pRealData = 0;
int nTimes = 0;
while ( pRealData = txtStack.pop() )
{
cout << (char*)pRealData << endl;
free( pRealData );
pRealData = 0;
nTimes ++;
if ( nTimes > nTimesLimit )
break;
}
cout << "now stack size: " << txtStack.size( ) << endl;
}
void destroy3( void * pData )
{
}
void testStack3( )
{
Stack intStack( destroy3 );
int intArray[ 5 ] = {1, 2, 3, 4, 5};
int nPos = 0;
for ( nPos = 0; nPos < 5; nPos ++ )
{
intStack.push( &intArray[nPos] );
}
cout << "stack size before pop: " << intStack.size() << endl;
int nTimesLimit = 2;
int nTimes = 0;
void * pData = 0;
while ( pData = intStack.pop() )
{
cout << *(int*)pData << endl;
nTimes ++;
if ( nTimes > nTimesLimit )
break;
}
cout << "stack size after pop: " << intStack.size() << endl;
}
集合初始化的几个例子:
int a[10] = {0}; //每个初化为0
struct AA
{
int aa;
float bb;
};
AA sA = {14, 1.0f}; //直接初始化
int a[] = {12, 13, 90};
则元素的个数为: sizeof a / sizeof *a