1、问题1
2、mutable
3、mutable分析
#include <iostream>
#include <string>
using namespace std;
class Test
{
int m_value;
int * const m_pCount;//技巧,对于const类对象和非const类对象都可以对该变量进行修改
/* mutable int m_count; */
public:
Test(int value = 0) : m_pCount(new int(0))
{
m_value = value;
/* m_count = 0; */
}
int getValue() const
{
/* m_count++; */
*m_pCount = *m_pCount + 1;
return m_value;
}
void setValue(int value)
{
/* m_count++; */
*m_pCount = *m_pCount + 1;
m_value = value;
}
int getCount() const
{
/* return m_count; */
return *m_pCount;
}
~Test()
{
delete m_pCount;
}
};
int main(int argc, char *argv[])
{
Test t;
t.setValue(100);
cout << "t.m_value = " << t.getValue() << endl;
cout << "t.m_count = " << t.getCount() << endl;
const Test ct(200);
cout << "ct.m_value = " << ct.getValue() << endl;
cout << "ct.m_count = " << ct.getCount() << endl;
return 0;
}
4、问题2
5、
6、重载new/delete
7、
8、
通过重载new/delete操作符来进行,在静态存储区创建对象
通过这样的方法结合二阶构造方法 可以创建单例模式以外的N例模式(只能存在N个对象)
#include <iostream>
#include <string>
using namespace std;
class Test
{
//定义一个静态成员空间的大小,可以容纳4个对象
static const unsigned int COUNT = 4;
static char c_buffer[];
static char c_map[];
int m_value;
public:
void* operator new (unsigned int size)
{
void* ret = NULL;
for(int i=0; i<COUNT; i++)
{
if( !c_map[i] )
{
c_map[i] = 1;
ret = c_buffer + i * sizeof(Test);
cout << "succeed to allocate memory: " << ret << endl;
break;
}
}
return ret;
}
void operator delete (void* p)
{
if( p != NULL )
{
char* mem = reinterpret_cast<char*>(p);
int index = (mem - c_buffer) / sizeof(Test);
int flag = (mem - c_buffer) % sizeof(Test);
if( (flag == 0) && (0 <= index) && (index < COUNT) )
{
c_map[index] = 0;
cout << "succeed to free memory: " << p << endl;
}
}
}
};
char Test::c_buffer[sizeof(Test) * Test::COUNT] = {0};
char Test::c_map[Test::COUNT] = {0};
int main(int argc, char *argv[])
{
cout << "===== Test Single Object =====" << endl;
Test* pt = new Test;
delete pt;
cout << "===== Test Object Array =====" << endl;
Test* pa[5] = {0};
for(int i=0; i<5; i++)
{
pa[i] = new Test;//只能创建4个对象,第5个为空
cout << "pa[" << i << "] = " << pa[i] << endl;
}
for(int i=0; i<5; i++)
{
cout << "delete " << pa[i] << endl;
delete pa[i];
}
return 0;
}
===== Test Single Object =====
succeed to allocate memory: 0x6021a0
succeed to free memory: 0x6021a0
===== Test Object Array =====
succeed to allocate memory: 0x6021a0
pa[0] = 0x6021a0
succeed to allocate memory: 0x6021a4
pa[1] = 0x6021a4
succeed to allocate memory: 0x6021a8
pa[2] = 0x6021a8
succeed to allocate memory: 0x6021ac
pa[3] = 0x6021ac
pa[4] = 0
delete 0x6021a0
succeed to free memory: 0x6021a0
delete 0x6021a4
succeed to free memory: 0x6021a4
delete 0x6021a8
succeed to free memory: 0x6021a8
delete 0x6021ac
succeed to free memory: 0x6021ac
delete 0
9、问题3
10、
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Test
{
static unsigned int c_count;
static char* c_buffer;
static char* c_map;
int m_value;
public:
static bool SetMemorySource(char* memory, unsigned int size)
{
bool ret = false;
c_count = size / sizeof(Test);
ret = (c_count && (c_map = reinterpret_cast<char*>(calloc(c_count, sizeof(char)))));
if( ret )
{
c_buffer = memory;
}
else
{
free(c_map);
c_map = NULL;
c_buffer = NULL;
c_count = 0;
}
return ret;
}
void* operator new (long unsigned int size)
{
void* ret = NULL;
if( c_count > 0 )
{
for(int i=0; i<c_count; i++)
{
if( !c_map[i] )
{
c_map[i] = 1;
ret = c_buffer + i * sizeof(Test);
cout << "succeed to allocate memory: " << ret << endl;
break;
}
}
}
else
{
ret = malloc(size);
}
return ret;
}
void operator delete (void* p)
{
if( p != NULL )
{
if( c_count > 0 )
{
char* mem = reinterpret_cast<char*>(p);
int index = (mem - c_buffer) / sizeof(Test);
int flag = (mem - c_buffer) % sizeof(Test);
if( (flag == 0) && (0 <= index) && (index < c_count) )
{
c_map[index] = 0;
cout << "succeed to free memory: " << p << endl;
}
}
else
{
free(p);
}
}
}
};
unsigned int Test::c_count = 0;
char* Test::c_buffer = NULL;
char* Test::c_map = NULL;
int main(int argc, char *argv[])
{
char buffer[12] = {0};
Test::SetMemorySource(buffer, sizeof(buffer));
cout << "===== Test Single Object =====" << endl;
Test* pt = new Test;
delete pt;
cout << "===== Test Object Array =====" << endl;
Test* pa[5] = {0};
for(int i=0; i<5; i++)
{
pa[i] = new Test;
cout << "pa[" << i << "] = " << pa[i] << endl;
}
for(int i=0; i<5; i++)
{
cout << "delete " << pa[i] << endl;
delete pa[i];
}
return 0;
}
===== Test Single Object =====
succeed to allocate memory: 0x7ffc2efe4ce0
succeed to free memory: 0x7ffc2efe4ce0
===== Test Object Array =====
succeed to allocate memory: 0x7ffc2efe4ce0
pa[0] = 0x7ffc2efe4ce0
succeed to allocate memory: 0x7ffc2efe4ce4
pa[1] = 0x7ffc2efe4ce4
succeed to allocate memory: 0x7ffc2efe4ce8
pa[2] = 0x7ffc2efe4ce8
pa[3] = 0
pa[4] = 0
delete 0x7ffc2efe4ce0
succeed to free memory: 0x7ffc2efe4ce0
delete 0x7ffc2efe4ce4
succeed to free memory: 0x7ffc2efe4ce4
delete 0x7ffc2efe4ce8
succeed to free memory: 0x7ffc2efe4ce8
delete 0
delete 0
11、
12、
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Test
{
int m_value;
public:
Test()
{
m_value = 0;
}
~Test()
{
}
//new重载后的参数size 代表当前对象所占内存的大小,由编译器算出,我们使用的时候不用传大小,
void* operator new (unsigned int size)
{
cout << "operator new: " << size << endl;
return malloc(size);
}
void operator delete (void* p)
{
cout << "operator delete: " << p << endl;
free(p);
}
//new[] 重载后的参数size 代表当前对象所占内存的大小,由编译器算出,size大于我们预估的内存大小,多余的内存主要用来存放数组的数据信息()长度等
void* operator new[] (unsigned int size)
{
cout << "operator new[]: " << size << endl;
return malloc(size);
}
void operator delete[] (void* p)
{
cout << "operator delete[]: " << p << endl;
free(p);
}
};
int main(int argc, char *argv[])
{
Test* pt = NULL;
pt = new Test;
delete pt;
pt = new Test[5];
delete[] pt;
return 0;
}
operator new: 4
operator delete: 0xb03030
operator new[]: 28
operator delete[]: 0xb03050
13、
14、小结
15、补充:关于new/delete操作符重载的解释
补充知识点:解决使用疑惑
函数(Function)
(1) operator new function
void * ::operator new(size_t); //Global
void * class-name::operator new(size_t); //Class
上面是C++中operator new function的原型,一个是全局类型的,一个的类成员类型的。全局类型的operator new函数在下面两种情况下被调用:一种是在分配C++内建(built-in)类型的动态内存时,一种是在分配用户没有自己定义operator new成员函数的用户自定义类型的动态内存时。 如果用户在自己定义的类型中,定义了operator new函数,那么用户在用new申请该类型的动态内存时, 便会调用该类型的成员函数operator new, 而不是全局的operator new。
另外,我们注意到,上面的原型中函数的返回值为void 类型, 第一个参数为size_t类型,这个是C++编译器要求的,如果要自己重载operator new函数,返回值必须为void 类型,第一个参数必须为size_t类型,否则,编译器会返回如下错误信息:(2) operator delete function
void operator delete( void * );
void operator delete( void *, size_t );
上面是operator delete function的原型。operator delete function也有全局的和类成员的两种。这里需要注意,一个类只能有一个operator delete function做为其成员函数,而且必须为上面两种中的其中一种,没有其它的形式。如果一个类实现了自己的operator delete function成员函数,那么在释放该类型的内存时,编译器便会调用成员operator delete function, 而不是全局的。
上面的两种原型,第一种,在调用的时候,编译器会把要释放的内存的首地址传入,第二种,在调用的时候,编译器会把要释放的内存的首地址和大小都传入。因此,可以利用这一特性,如果我们在基类中实现第二种形式的operator delete function的成员函数,那么便可以用之来释放子类类型的内存(具体参考最后面的例子)。
2. 运算符(Operator)
(1) new operator
[::] new [placement] new-type-name [new-initializer]
[::] new [placement] ( type-name ) [new-initializer]
注:上面的’[]‘表示在其中的部分是optional(可选的)
上面是new operator的原型。在C++中,动态内存的分配,通常都是调用new operator来完成的,利用new operator来分配动态内存,编译器要做下面两项工作:
a. 调用operator new function分配内存(allocate the memory)
b. 调用构造函数(call the constructor)来进行初始化
下面来说一说new operator的原型中各部分到底是干什么的:
placement: 如果你重载了operator new function, placement可以用来传递额外的参数
type-name: 指定要分配的内存的类型,可以是内建(built-in)类型,也可以是用户自定义类型
new-initializer: 指定对分配后内存的初始化的参数,也就的构造函数的参数 。这里需要注意一点,在分配一个对象的数组类型的内存时,不能够指定初始化参数;换言之,要想分配一个对象的数组类型的内存,该对象必须有缺省构造函数
(2) delete opeartor
[::] delete cast-expression
[::] delete [ ] cast-expression
上面是delete operator的原型,第一种用来释放普通的对象(包括内建类型)类型的内存,第二种用来释放对象的数组类型的内存。在C++中,用new operator分配的动态内存,必须调用delete operator来释放,通常用delete operator释放内存编译器要做下面两项工作:
a. 调用对象析构函数来析构对象
b. 调用operator delete function来释放内存(deallocate the memory)3. 关于new/delete使用过程中一些需要注意的点
(1)如何区别operator new/delete function 与 new/delete operator ?
通过上面的讲述,不难看出,我们分配/释放动态内存,调用的是new/delete operator, 而在调用new/delete的过程中,编译器会自动调用operator new/delete function来完成实际的内存分配/释放的工作
(2) 用delete operator去释放一块不是由new operator释放的内存,结果是不可预料的,因此,切记,operator new与operator delete一定要配对使用,这是写好程序的基础
(3) new operator调用失败会抛出std::bad_alloc异常,前提是你没有自己重载对应的operator new function;delete operator失败,常见的原因是多次delete同一块内存
(4) 如果一块内存被delete后,再对它解引用(Dereference),结果也是不可预测的,很可能导致程序崩溃
(5) delete一个空(NULL)指针是安全的,没有任何害处的
(6) 类成员类型的operator new/delete函数必须为静态(static)函数,因此它们不能为虚函数(virtual function),也遵守public, protected, private的访问权限控制