构造系列和位拷贝使用注意

博客主要探讨C++构造函数相关问题。一是浅拷贝构造带来的问题,如内存无法释放、析构错误等,建议有指针成员时写自定义拷贝构造函数,参数使用引用传递;二是伪构造初始化序列问题,包括构造顺序、模板特殊性等,给出了使用const成员、注意构造顺序等建议。

构造函数之一: 构造函数本身很多内容时间关系先整理一部分,自己的理解。后面的慢慢的再写出来讨论讨论。这里主要讲了 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的话.还可以在构造函数体内处理比较好。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值