智能指针+拷贝构造+vector容器+多态引起的bug

这篇具有很好参考价值的文章主要介绍了智能指针+拷贝构造+vector容器+多态引起的bug。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

今天在调试一段代码的时候,VC编译提示:

error C2280: “T485CommCtrlPara::T485CommCtrlPara(const T485CommCtrlPara &)”: 尝试引用已删除的函数

函数执行部分如下:

智能指针+拷贝构造+vector容器+多态引起的bug

 看意思是这个pComm485Pro已经消亡了,后续push_back到vec485DevCommPara有问题,但智能指针已经move了,这样new出来资源的所有权应该已经转移了,为啥还会有问题呢?

找了下chatgpt和newbing查了下,他提供了一个馊主意:

智能指针+拷贝构造+vector容器+多态引起的bug

 这个是把智能指针转成普通指针操作一把,后续还要delete,得不偿失,而且只是编译通过,问题依然存在。

本文就针对这个问题,详细分析下,先把有问题代码精简下,贴出来:

#include <iostream>
#include <string>
#include <vector>
#include <memory>

typedef struct {
    std::string strPortName;
    unsigned int dwBaudRate;
    unsigned char bByteSize;
    unsigned char bStopBits;
    unsigned char bParity;
} TCommPara;

class CComm
{
public:
    config(){;};
} 

class CMeterProto
{
;
}

class cModbusProto:public CMeterProto
{
public:
    CModbusProto(const unsigned char bBAPn, const TCommPara tCommPara)
    : m_bBAPn(bBAPn), m_tCommPara(tCommPara) 
    {
    }
private:
    unsigned char m_bBAPn;
    TCommPara m_tCommPara;
}

typedef struct {
    std::unique_ptr<CMeterProto> pComm485Pro{nullptr};
    CComm cMterCom;
}T485CommCtrlPara;

int LoadBA485CommPara(TCommPara &tCommPara, T485CommCtrlPara &t485CommPara, vector<T485CommCtrlPara>& vec485DevCommPara)
{
    tCommPara.strPortName = "com1";
    tCommPara.dwBaudRate = 9600;
    tCommPara.bByteSize = 8;
    tCommPara.bStopBits = 1;
    
    t485CommPara.cMterCom.config();
    std::unique_ptr<CMeterProto> pComm485Pro(new CModbusProto(1, tCommPara));
    t485CommPara.pComm485Pro = std::move(pComm485Pro);
    vec485DevCommPara.push_back(t485CommPara);
    
    return 1;
}

int main()
{
    TCommPara tCommPara;
    T485CommCtrlPara t485CommPara;
    vector<T485CommCtrlPara> vec485DevCommPara;
    
    int nBaNum = LoadBA485CommPara(tCommPara, t485CommPara, vec485DevCommPara);
    
    std::count<<nBaNum<<std::endl;
}

通过将如上代码交给chatgpt分析,开始他巴拉巴拉说没啥问题,后来我把VC的编译信息交给他

如上代码,在vs 2015上编译,提示:error C2280: “T485CommCtrlPara::T485CommCtrlPara(const T485CommCtrlPara &)”: 尝试引用已删除的函数

这个时候它开始分析代码了,经过几轮的修改,他终于还是发现了是push_back的问题。

主要原因就是push_back本质上是调用拷贝构造函数,将资源拷贝到vector的堆空间上,如果使用默认拷贝函数,就是浅拷贝,不会将pComm485Pro的资源拷贝过去,所以push_back拷贝的只是一个地址,实际资源并没有拷贝

原因知道后,修改就很简单了,实现拷贝构造函数即可,如上的

typedef struct {
    std::unique_ptr<CMeterProto> pComm485Pro{nullptr};
    CComm cMterCom;
}T485CommCtrlPara;

要定义下拷贝构造函数,按照chatgpt的实现,

T485CommCtrlPara(const T485CommCtrlPara& other)
        : pComm485Pro(other.pComm485Pro ? std::make_unique<CMeterProto>(*other.pComm485Pro) : nullptr),
          cMterCom(other.cMterCom)
    {
        // 在自定义拷贝构造函数中,正确拷贝智能指针成员
    }

编译不了,因为直接在struct中定义拷贝构造,vc编译还有问题,既然如此,修改成类方式好了:

智能指针+拷贝构造+vector容器+多态引起的bug

  如上,编译后的时候提示了一个问题:

error C2512: “T485CommCtrlPara”: 没有合适的默认构造函数可用

这个就是常见的三法则了,如果手动定义了拷贝构造,编译器将不再自动生成默认构造,此处需要添加上:

智能指针+拷贝构造+vector容器+多态引起的bug

 就可以正常运行了。

按照如上方式,修改实际工程中的代码,发现一个问题:

error C2259: “CMeterProto”: 不能实例化抽象类

这个就是CMeterProto中有一个纯虚函数:

virtual int GetData() = 0;

因为抽象类在new的时候无法指向具体的位置,导致实例化类失败,修改为普通虚函数就可以了:

virtual int GetData() {return 0};

如上,修改完成后就都编译,运行成功了。

将全部代码贴下来吧:

智能指针+拷贝构造+vector容器+多态引起的bug

智能指针+拷贝构造+vector容器+多态引起的bug

智能指针+拷贝构造+vector容器+多态引起的bug

 总结:

1:使用智能指针可以通过std::move转移所有权。

2:使用vector变量push_back一个对象或变量的时候,本质上是执行拷贝构造。

3:如果对象中有申请资源时,如果new内存,句柄等,需要手动实现拷贝构造

4:抽象类不能new实例

5:碰到问题的时候,一心指望chatgpt是不够的,自己对于基本原理还是要门清,否则带去沟里也不知道文章来源地址https://www.toymoban.com/news/detail-503489.html

到了这里,关于智能指针+拷贝构造+vector容器+多态引起的bug的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 拷贝构造函数(深拷贝+浅拷贝)

    拷贝构造函数: 浅拷贝的思路就是和默认的拷贝构造函数一样: 即将原对象的值直接赋值给新对象,这样做一般情况下是没什么问题的,但是如果类的成员有指针,就会导致新对象中的指针和原对象中的指针指向的是一个地址.这样就会有若干风险存在 对新对象中的指针内容

    2024年02月09日
    浏览(28)
  • 【C++学习】类和对象 | 拷贝构造 | 探索拷贝构造函数为什么需要引用传参 | 深拷贝 | 初识运算符重载

    上一篇文章我们开始学习类内的默认成员函数, 这里是传送门,有兴趣可以去看看:http://t.csdn.cn/iXdpH 这篇文章我们继续来学习类和对象的知识。 目录 写在前面: 1. 拷贝构造 2. 拷贝构造函数为什么需要引用传参? 3. 深拷贝 4. 初识运算符重载 写在最后: 我们在创建一个对

    2024年02月11日
    浏览(38)
  • C++ 构造函数实战指南:默认构造、带参数构造、拷贝构造与移动构造

    构造函数是 C++ 中一种特殊的成员函数,当创建类对象时自动调用。它用于初始化对象的状态,例如为属性分配初始值。构造函数与类同名,且没有返回值类型。 C++ 支持多种类型的构造函数,用于满足不同的初始化需求: 默认构造函数: 不带参数的构造函数,通常用于初始化

    2024年04月22日
    浏览(35)
  • C++——拷贝构造函数

    (用旧对象去构造新对象) 拷贝构造函数,又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构造及初始化。 参数的类型:   值类型(不行,会产生递归); 指针类型(能实现要求,但会出现歧义(感觉a的地址给b构造));

    2024年02月02日
    浏览(26)
  • 【C++】详解拷贝构造

    拷贝构造的功能 写法: 拷贝构造函数的参数为什么是引用类型 系统自动生成的拷贝构造函数 拷贝构造的深拷贝与浅拷贝 概念 浅拷贝: 深拷贝 小结 拷贝构造函数 可以把曾经 实例化好的对象的数据 拷贝给 新创建的数据 ,可见说拷贝构造函数在功能上是构造函数的另一种

    2024年04月24日
    浏览(23)
  • 『C++成长记』拷贝构造函数

     🔥 博客主页: 小王又困了 📚 系列专栏: C++ 🌟 人之为学,不日近则日退 ❤️ 感谢大家点赞👍收藏⭐评论✍️ 目录 一、拷贝构造函数 📒1.1拷贝构造函数的概念 📒1.2拷贝构造函数的写法 📒1.3编译器生成的拷贝构造 📒1.4拷贝构造函数的用法 📒1.5拷贝构造函数典型调

    2024年02月04日
    浏览(31)
  • C++ 类和对象(二)构造函数、析构函数、拷贝构造函数

            本文将介绍类的6个默认成员函数中的构造函数、析构函数和拷贝构造函数,赋值重载和取地址重载涉及运算符重载的知识,将在下篇讲解。所谓默认成员函数,也就是每个类都有的成员函数,我们可以显式定义这些函数,否则,编译器会自动生成它们。 目录 前言

    2024年02月09日
    浏览(33)
  • 【C++初阶】类和对象——构造函数&&析构函数&&拷贝构造函数

    ========================================================================= 个人主页点击直达: 小白不是程序媛 C++系列专栏: C++头疼记 ========================================================================= 目录 前言 类的6个默认成员函数 构造函数 概念 构造函数的特性 析构函数 概念 析构函数特性 拷贝构

    2024年02月06日
    浏览(37)
  • vector的构造函数

    (1)默认构造,无需传参 vectorint v1;        // 此时还没有分配空间 (2)vectorint v2(n);        // 分配了空间 ,指定元素个数,默认值为0 vectorint v2(n, -1);        //指定元素个数和值 (3)构造函数传入两个参数,分别为一段序列的起始地址或迭代器和结束地址或迭代器。

    2024年02月13日
    浏览(29)
  • 【C++】类与对象(构造函数、析构函数、拷贝构造函数、常引用)

       🌈个人主页: 秦jh__https://blog.csdn.net/qinjh_?spm=1010.2135.3001.5343 🔥 系列专栏:   目录 类的6个默认成员函数 构造函数 特性  析构函数 特性  析构的顺序 拷贝构造函数 特性 常引用      💬 hello! 各位铁子们大家好哇。              今日更新了类与对象的构造函数、

    2024年02月21日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包