C++ 浅拷贝这个坑

2018.5.13

在测试策略模式的多对象时,我用到了 vectorpush_back 以及 emplace_back 以及 listpush_backemplace_back
没想到测试的主要时间花费在了调试程序上!

Bug 程序如下

#include <iostream>
#include <vector>
#include <list>
#define rep( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
#define dew( i , j , n ) for ( int i = int(n-1) ; i > int(j) ; --i )
#define _PATH __FILE__ , __LINE__
typedef std::pair < int , int > P ;
using std::cin ;
using std::cout ;
using std::endl ;

class Strategy {
public:
    virtual void Login () = 0 ;
    virtual ~Strategy () = default ;
} ;

class Teacher_Login : public Strategy {
public:
    void Login () {
        cout << endl << "教师登录" << endl ;
    }
} ;

class Student_Login : public Strategy {
public:
    void Login () {
        cout << endl << "学生登录" << endl ;
    }
} ;

class Admin_Login : public Strategy {
public:
    void Login () {
        cout << endl << "管理员登录" << endl ;
    }
} ;

class Login_System {
private:
    Strategy* strategy ;
public:
    explicit Login_System ( Strategy* _strategy = nullptr )
        : strategy ( _strategy )
    {}
    void Call_strategy () {
        if ( strategy )
            strategy->Login () ;
        else 
            cout << endl << "登录策略为 nullptr\n" ,
            cout << __FILE__ << "\t 第  " << __LINE__ << "  行" << endl ;
    }
    void Change ( Strategy* _strategy = nullptr ) {
        if ( strategy != nullptr )
            delete strategy ;
        strategy = _strategy ;
    }
    ~Login_System () {
        if ( strategy != nullptr ) 
            delete strategy ;
        strategy = nullptr ;
    }
} ;

int main () {
    std::vector< Login_System > YHL ;
    rep ( i , 0 , 3 ) 
        YHL.emplace_back ( new Teacher_Login () ) ; 
    rep ( i , 0 , 2 ) 
        YHL.emplace_back ( new Student_Login () ) ;
    rep ( i , 0 , 2 )
        YHL.emplace_back ( new Admin_Login () ) ;
    for ( auto &it : YHL )
        it.Call_strategy () ;
    YHL.clear () ;
    return 0 ;
}

看似正常的程序一直崩溃!
分析

std::vector + push_back 会崩溃
std::vector + emplace_back 会崩溃
std::list + push_back 会崩溃
std::list + emplace_back 正常 !

调试输出,问题出在析构函数几次释放了 strategy 指针
???
为什么 std::list + emplace_back 就正常呢 ?
1. push_back 的参数是 value_typevalue_type&& ,如果不是右值引用,那就是拷贝构造函数,而且是浅拷贝
2. emplace_back 是就地构造,不会调用拷贝构造函数,所以std::list + emplace_back正常
???
为什么 std::vector + emplace_back 也不行呢?
1. 我没写深拷贝函数,平时经常说浅拷贝,深拷贝,结果防不胜防,以此做警惕
2. std::vector 就是一个顺序表,会经常扩容,调用容器元素的析构函数,即使是 emplace_back 也一样会扩容,销毁原来的,重新找块空间

教训

  1. 对象内部有指针的情况,一定要判断是否需要深拷贝!!!
  2. 容器内最好不要放实体,应尽量放指针,一来可以减小拷贝赋值的消耗,二来,要注意容器插入 value_type 会自动调用拷贝构造函数。
  3. 尽量少用 std::vector ,一是因为它经常扩容,消耗大;二来它的经常扩容很容易导致指针之间的浅拷贝

修改后的程序

#include <iostream>
#include <typeinfo>
#include <vector>
#include <list>
#define rep( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
#define dew( i , j , n ) for ( int i = int(n-1) ; i > int(j) ; --i )
#define _PATH __FILE__ , __LINE__
typedef std::pair < int , int > P ;
using std::cin ;
using std::cout ;
using std::endl ;

class Strategy {
public:
    virtual void Login () = 0 ;
    virtual ~Strategy () = default ;
} ;

class Teacher_Login : public Strategy {
public:
    void Login () {
        cout << endl << "教师登录" << endl ;
    }
} ;

class Student_Login : public Strategy {
public:
    void Login () {
        cout << endl << "学生登录" << endl ;
    }
} ;

class Admin_Login : public Strategy {
public:
    void Login () {
        cout << endl << "管理员登录" << endl ;
    }
} ;

class Login_System {
private:
    Strategy* strategy ;
public:
    explicit Login_System ( Strategy* _strategy = nullptr )
        : strategy ( _strategy )
    {}
    void Call_strategy () {
        if ( strategy )
            strategy->Login () ;
        else 
            cout << endl << "登录策略为 nullptr\n" ,
            cout << __FILE__ << "\t 第  " << __LINE__ << "  行" << endl ;
    }
    void Change ( Strategy* _strategy = nullptr ) {
        if ( strategy != nullptr )
            delete strategy ;
        strategy = _strategy ;
    }
    ~Login_System () {
        if ( strategy != nullptr ) 
            delete strategy ;
        strategy = nullptr ;
    }
    Login_System ( const Login_System& One ) {   // 对应的拷贝构造函数
        if ( One.strategy != nullptr ) {
            if ( typeid ( *One.strategy ) == typeid ( Teacher_Login ) ) 
                this->strategy = new Teacher_Login () ;
            else if ( typeid ( *One.strategy ) == typeid ( Student_Login ) )
                this->strategy = new Student_Login () ;
            else 
                this->strategy = new Admin_Login () ;
        }
    }
    Login_System ( Login_System&& One ) : strategy ( One.strategy ) {
        One.strategy = nullptr ;
    }
} ;

int main () {
    std::vector< Login_System > YHL ;
    rep ( i , 0 , 3 ) 
        YHL.emplace_back ( new Teacher_Login () ) ; 
    rep ( i , 0 , 2 ) 
        YHL.emplace_back ( new Student_Login () ) ;
    rep ( i , 0 , 2 )
        YHL.emplace_back ( new Admin_Login () ) ;
    for ( auto &it : YHL )
        it.Call_strategy () ;
    YHL.clear () ;
    return 0 ;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值