前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从一道面试题看深拷贝构造函数问题(以vector为例)

从一道面试题看深拷贝构造函数问题(以vector为例)

作者头像
程序员小王
发布2021-03-22 12:23:58
7870
发布2021-03-22 12:23:58
举报
文章被收录于专栏:架构说架构说

大家好,

阅读本文章后在类的深度拷贝获得收益,下面是是章节内容

问题,如何为map 添加一个自定的key?你想到了什么

map 添加一个自定义key

  1. 容器是值传递,需要增加自定义类的拷贝构造函数。(这个不容易想到)
  2. map内部是有序的,新增一个函数对象 类比较大。

问题2 请看下面的程序,说说会出现什么问题?

代码语言:javascript
复制
#include <iostream>
#include <cstdlib>
#include <vector>  
using   namespace   std;  
 
class   CDemo  
{  
public:  
    CDemo(char*str=NULL)
 {
        
  if (str==NULL)//当初始化串不存在的时候,为m_data申请一个空间存放'\0';  
  {  
   m_str=new char[1];  
   *m_str='\0';  
  }  
  else//当初始化串存在的时候,为m_data申请同样大小的空间存放该串;  
  {  
   int length=strlen(str);  
   m_str=new char[length+1];  
   if (m_str==NULL)  
   {//内存是否申请成功    
    cout<<"申请内存失败!"<<endl;    
    exit(1);    
   }  
   strcpy(m_str,str);  
  }  
 }  
    ~CDemo()   
    {   
        if(m_str)   delete[]   m_str;   
    }  
 void show();
 
private:
    char*   m_str;  
};  
void CDemo::show()
{
 cout<<m_str<<endl;
}

int   main(int   argc,   char**   argv)  
{  
   CDemo   d1="trend   micro";  
   d1.show();
    
    vector<CDemo>   *a1=new   vector<CDemo>();  
  
    a1->push_back(d1); //here
    
    delete   a1; 
 
    return 0;
}

上述代码运行时出错。

代码语言:javascript
复制
a1 -> push_back(d1); //析构一次

是在a1所指的向量的尾部插入一个CDemo对象d,d的值与d1相等(调用默认拷贝构造函数,是浅拷贝),自然d.str=d1.str,即都指向同一内存地址。

代码语言:javascript
复制
delete a1;//析构一次

会调用vector<>的析构函数~vector(),在~vector()中也一定释放了各CDemo元素的内存空间(调用每个元素的~CDemo())

,这里由于vector中只有一个元素,故只调用一次~CDemo(),

这使得d.str被释放一次。 接着,因为d1是个局部变量,在main函数退出后,d1析构函数~CDemo()被调用,而d1.str所指内存空间已经在前面被释放,

所以会出现运行时错误。

问题3:局部变量和临时变量各自 delete 一次

代码语言:javascript
复制
class String {
public:
    String(const char* str) {
        cout << "String construct" << endl;
        m_data = new char[strlen(str) + 1];
        strcpy(m_data, str);
    }
  /**  
  String(const String& str) {
        cout << "String copy construct" << endl;
        m_data = new char[strlen(str.m_data) + 1];
        strcpy(m_data, str.m_data);
    }**/
    ~String() {
        cout << "String destroy" << endl;
        delete[] m_data;
    }
private:
    char* m_data;
};

void main() {
    vector<String> vec;
    for (int i = 0; i < 1; i++) {
        String str("hello");
        vec.push_back(str);
    }

    cout << "end" << endl;
}

1)如果类的成员变量都是基本数据类型,浅拷贝没有任何问题;

2)如果类的成员变量包含指针或者引用,那么对这个类的对象使用时就要注意了,浅拷贝只会拷贝指针或引用本身,而不会拷贝指针或引用所指向的对象, 这样就会导致多个对象同时持有指向某个对象的指针, 容易引发在释放该对象时,出现多次释放同一对象,或者内存泄漏。

代码语言:javascript
复制
(gdb) bt
#0 0x0000003f0b02e2ed in raise () from /lib64/tls/libc.so.6
#1 0x0000003f0b02fa3e in abort () from /lib64/tls/libc.so.6
#2 0x0000003f0b062d41 in __libc_message () from /lib64/tls/libc.so.6
#3 0x0000003f0b06881e in _int_free () from /lib64/tls/libc.so.6
#4 0x0000003f0b068b66 in free () from /lib64/tls/libc.so.6
#5 0x000000342cfae19e in operator delete () from /usr/lib64/libstdc++.so.6

问题4: 右值是什么鬼?

右值引用 就是引用 放在哪里?

肯定是栈上,通过名字就能直接

代码语言:javascript
复制
template<typename _Tp>  
inline typename std::remove_reference<_Tp>::type&&  
move(_Tp&& __t)  
{ 
    return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); 
}

右值 放在哪里? 寄存器 或者立即数

访问速度快呀

总结

  • STL容器所提供的都是值(value)寓意,而非引用(reference)寓意,

也就是说当我们给容器中插入元素的时候容器内部实施了拷贝动作, 将我们要插入的元素再另行拷贝一份放入到容器中,

而不是将原数据元素直接放进容器中,也就说我们提供的元素必须能够被拷贝。

  • c++11支持 move copy动作。
  • https://godbolt.org/z/fd8KMT 临时变量 程序无法直接访问,那cpu怎么访问的。数据在内存中分配 立即数 寄存器 堆栈 和代码段。

播种希望

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Offer多多 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题,如何为map 添加一个自定的key?你想到了什么
  • 问题2 请看下面的程序,说说会出现什么问题?
  • 问题3:局部变量和临时变量各自 delete 一次
  • 右值引用 就是引用 放在哪里?
  • 肯定是栈上,通过名字就能直接
  • 右值 放在哪里? 寄存器 或者立即数
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档