构造函数之一: 构造函数本身很多内容时间关系先整理一部分,自己的理解。后面的慢慢的再写出来讨论讨论。这里主要讲了 copy构造,和序列初始化一些问题。希望大家注意。
2004-12-2 20:00
<1>浅拷贝构造带来的问题: bitwise copy 《effective c++》上使用这个名词来描述,只看原版还是好理解的,翻译过来我就使用浅拷贝吧。简单定义我认为是: 所有成员对象的简单复制。
通过例子来说吧
class A
{
public:
A( const char* ip_c );
~A() ;
private:
char* mp_c;
};
A::A( const char* ip_c )
{
if(ip_c)
{
mp_c = new char[strlen(ip_c)+1];
strcpy( mp_c, ip_c );
}
else
mp_c = new char('/0');
}
A::~A()
{
if(mp_c)
delete[] mp_c;
mp_c = NULL;
}
int main(int argc, char* argv[])
{
A t_a_1 = "test1"; //这个没有问题 构造函数构造出A 对象并且 A::mp_c开辟空间
A t_a_2 = "test2"; //也没问题 构造出A对象 A::mp_c另外开辟空间
t_a_1 = t_a_2;
//这个地方因为没有copy construct 或是 operate =
//只有调用默认编译器加入的拷贝构造函数进行成员拷贝
//我们只抓住重点,如果是对象进行拷贝一切都没有问题,因为对象拷贝
//必须重新分配空间不存在共享一块空间情况。但是注意这个成员是指针
//这个时候指针拷贝仅仅四个字节的内容复制相当于指针赋值,而没有
//进行重升新对t_a_1.mp_c释放空间后重新分配然后拷贝t_a_2.mp_c内容进去
return 0;
}
//产生问题1:由于简单将t_a_1.mp_c = t_a_2.mp_c原先的t_a_1.mp_c的地址丢失,内存无//法释放
//产生问题2:由于简单赋值使得两个对象的内存指针指向同一块地址。在结束后对象析构//delete[]发生
//两次造成错误。
//潜在问题: 任意一次函数调用中对于 A进行一次值传递,就会出问题2错。
//建议1: 如果有指针成员的构造函数请写上自定义copy costruct,进行完全拷贝。避免带//来问题
//建议2 : 如果想使用, 请在参数使用时引用传递。避免产生临时对象析构 释放多次。
<2> 伪构造初始化序列。这个初始化序列如果不注意时不时的会发生些小问题。让人觉得很困惑。偶就经常碰到。所以将这个问题提出来让没有意识到自己要明白怎么做,不要和偶一样犯同样的错误。
#include <iostream>
#include <vector>
using namespace std;
class C
{
public:
C() {}
C( C& ) { cout<<"C:"<<endl; }
};
class D
{
public:
D() {}
D(D&) { cout<<"D:"<<endl; }
};
class A
{
public:
A( C& i_c, D& i_d ) : m_c(i_c), m_d(i_d) {}
//一般不含有类模板构造序列从左到右 //依次执行 大家可以执行看下,但是如果 //构造函数中有了模板将优先执行模板构造
A( int i_i, const char* i_p_c ): m_i(i_i), m_s(i_p_c) {}
//这里首先执行m_s的构造然后依次m_i
//因为有了模板的特殊顺序存在序列化时
//要特别小心。m_s的const性必须在序列化
//时构造。
A( int i_i ) : m_i(i_i), m_v(m_i) {}
//这里构造优先m_v,如果m_i不是静态的将会出错
//这里也隐含了一个隐式转化的问题下面说明
private:
vector<int> m_v;
int m_i;
const string m_s;
C m_c;
D m_d;
};
void main()
{
int t_i = 5;
const char* t_p_c = "const";
C t_c;
D t_d;
A t_a_t( t_c, t_d );
A t_a_c( t_i, t_p_c );
//A t_a_s(t_i); //这句构造时因为优先构造m_t,此时m_i还未被构造是随即数
//vector 在allocator时会出错。
}
建议使用:
1. const 成员只能序列化时初始化,不要企图在构造函数体内处理。除非搞欺骗
2.序列构造顺序性,所以大家使用时注意顺序,不要将对象建立在未构造的对象之上
3.模板在序列化时的特殊性,使用时用传入参数构造m_v(i_i)这样,尽量不要使用成员
如果不是static的话.还可以在构造函数体内处理比较好。