天道酬勤,学无止境

C++:Coverity 报告因引用和容器的特殊使用而导致的泄漏(C++ : Coverity reports leaks for peculiar use of references and containers)

问题
int main() { ... B* b = ... // (1) Coverity: Storage is returned from // allocation function operator new // (2) Coverity: Assigning ... A* a = new A(); // (3) Coverity: noescape: Resource a is not freed // or pointed-to in add_a_to_b b->add_a_to_b( *a ); ... // (4) Coverity: Resource leak: Variable a going out // of scope leaks the storage it points to. } class B { public: std::vector<A> a_vector; void add_a_to_b( const A& a ) { a_vector.push_back( a ); }
回答1

您有内存泄漏,因为您调用了new而没有调用delete 。 此外,您没有理由调用new或动态分配。 您可以简单地自动分配a 。 这同样适用于b

B b;
A a;

...   
b.add_a_to_b(a); // b stores a copy of `a`.
回答2
delete a; // Do this when you don't need a anymore.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 使用 C++ 字符串可能出现内存泄漏(Possible memory leak using C++ string)
    问题 考虑以下 C++ 程序: #include <cstdlib> // for exit(3) #include <string> #include <iostream> using namespace std; void die() { exit(0); } int main() { string s("Hello, World!"); cout << s << endl; die(); } 通过 valgrind 运行它显示了这一点(为简洁起见,一些输出被修剪): ==1643== HEAP SUMMARY: ==1643== in use at exit: 26 bytes in 1 blocks ==1643== total heap usage: 1 allocs, 0 frees, 26 bytes allocated ==1643== ==1643== LEAK SUMMARY: ==1643== definitely lost: 0 bytes in 0 blocks ==1643== indirectly lost: 0 bytes in 0 blocks ==1643== possibly lost: 26 bytes in 1 blocks ==1643== still reachable: 0 bytes in 0 blocks ==1643==
  • C++ 内存管理
    C++内存管理 [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不在,内存泄漏几乎在每个C++程序中都会发生,因此要想成为C++高手,内存管理一关是必须要过的,除非放弃C++,转到Java或者.NET,他们的内存管理基本是自动的,当然你也放弃了自由和对内存的支配权,还放弃了C++超绝的性能。本期专题将从内存管理、内存泄漏、内存回收这三个方面来探讨C++内存管理问题。 1 内存管理 伟大的Bill Gates 曾经失言:   640K ought to be enough for everybody — Bill Gates 1981 程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本文的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理。 1.1 C++内存管理详解 1.1.1 内存分配方式 1.1.1.1 分配方式简介   在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。   栈,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放
  • C++ 库实现如何在程序退出时分配内存但不释放它?(How does a C++ library implementation allocate memory but not free it when the program exits?)
    问题 代码相当简单: #include <vector> int main() { std::vector<int> v; } 然后我在 Linux 上使用 Valgrind 构建并运行它: g++ test.cc && valgrind ./a.out ==8511== Memcheck, a memory error detector ... ==8511== HEAP SUMMARY: ==8511== in use at exit: 72,704 bytes in 1 blocks ==8511== total heap usage: 1 allocs, 0 frees, 72,704 bytes allocated ==8511== ==8511== LEAK SUMMARY: ==8511== definitely lost: 0 bytes in 0 blocks ==8511== indirectly lost: 0 bytes in 0 blocks ==8511== possibly lost: 0 bytes in 0 blocks ==8511== still reachable: 72,704 bytes in 1 blocks ==8511== suppressed: 0 bytes in 0 blocks ... ==8511== ERROR
  • C++静态代码分析工具横向对比
    1 前言 静态代码分析是指无需运行被测代码,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,找出代码隐藏的错误和缺陷,如参数不匹配,有歧义的嵌套语句,错误的递归,非法计算,可能出现的空指针引用等等。统计证明,在整个软件开发生命周期中,30% 至 70% 的代码逻辑设计和编码缺陷是可以通过静态代码分析来发现和修复的。 在C++项目开发过程中,因为其为编译执行语言,语言规则要求较高,开发团队往往要花费大量的时间和精力发现并修改代码缺陷。所以C++ 静态代码分析工具能够帮助开发人员快速、有效的定位代码缺陷并及时纠正这些问题,从而极大地提高软件可靠性并节省开发成本。 静态代码分析工具的优势 : 1. 自动执行静态代码分析,快速定位代码隐藏错误和缺陷。 2. 帮助代码设计人员更专注于分析和解决代码设计缺陷。 3. 减少在代码人工检查上花费的时间,提高软件可靠性并节省开发成本。 2 主流业内C++静态代码分析工具横向对比 序号名称流行度跨平台性是否收费能否与SonarQube或GitLab集成能否自定义及扩展主要特点1cppcheck主流Windows/linuxfree能直接与sonar-cxx集成能扩展、能自定义侧重点于检查代码的逻辑支持的一些检查包括: 1.动变量检查 2.数组越界的界限检查 3.类检查(如:未使用的函数、变量初始化和内存复制) 4.Open
  • 牛客网:C++面试宝典——基础知识(8)C++11
    牛客网链接 ● 请问C++11有哪些新特性? 参考 1.初始化列表 参考 在C++98中,标准允许使用花括号{}来对数组元素进行统一的集合(列表)初始化操作 列表初始化的方式对:内置类型(int、float、double、char等)、数组、自定义的类、函数参数列表、STL标准模板库等都是有效的。 CClass::CClass() : x(0), y(1){ } 为什么要有列表初始化 (1)设想你有一个类成员C,而且只有一个带一个参数的构造函数。 如果C是另一个类的成员,你怎样初始化它呢?答案是你必须使用成员初始化列表。 (2)如果在构造函数内部赋值: 编译器总是确保所有成员在构造函数体执行之前被初始化,在到达赋值语句前完成就调用过相应的函数了 也就是需要调用两次函数,浪费资源 注:初始化顺序——按照声明的顺序初始化的,而不是按照出现在初始化列表中的顺序。 2.auto关键字 参考2 auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型。 auto 变量必须在定义时初始化。 3.for循环:for(auto c:nums),对容器也适用 4.nullptr关键字 参考3 C++11新标准中又引入了nullptr来声明一个“空指针”。 原因:NULL在C++中的定义,NULL在C++中被宏定义为整数0:在遇到重载时可能会出现问题。
  • Java 游戏引擎 [关闭](Java Game Engines [closed])
    问题 关闭。 这个问题需要更加集中。 它目前不接受答案。 想改善这个问题吗? 更新问题,使其仅通过编辑这篇文章来关注一个问题。 3年前关闭。 改进这个问题 我最近一直在研究游戏开发,我的第一门编程语言是 Java。 在玩了许多用 C++ 开发的令人惊叹的游戏后,我想知道为什么 Java 没有在游戏行业中大量使用。 我查看了 jMonkeyEngine 3 和其他一些游戏引擎环境,但我看到的屏幕截图远没有那么惊艳。 EA 的《极品飞车》和《刺客信条》等游戏都传达了这种真实感。 为什么Java做不出这样的行业实力游戏? 是艺术作品吗? Java 和 C# 具有自动垃圾收集功能,而 C++ 没有。 程序员必须密切关注内存使用情况,以避免出现悬空指针等问题。 谢谢你们。 回答1 Java 和 C# 具有自动垃圾收集功能,而 C++ 没有。 程序员必须密切关注内存使用情况,以避免出现悬空指针等问题。 你自己已经回答了你的问题。 在游戏编程中垃圾收集不是一个优势。 即使 Java 的性能在大多数任务上或多或少与 C++ 相当,而且 JIT 甚至可以进行非常积极的优化,击败静态分析期间可以完成的优化; 垃圾收集可以使帧率在最糟糕的时刻下降。 此外,对于图形密集型任务,Java 不是很合适,因为运行时认为许多事情是不安全的,因此被禁止(例如强制转换指针以重新解释数据)。
  • C++ 程序因 std::bad_alloc 而死亡,但 valgrind 报告没有内存泄漏(C++ program dies with std::bad_alloc, BUT valgrind reports no memory leaks)
    问题 我的程序失败并显示“std::bad_alloc”错误消息。 该程序是可扩展的,所以我用 valgrind 在较小的版本上进行了测试,没有内存泄漏。 这是统计力学的一个应用,所以我基本上是在制作数百个对象,更改它们的内部数据(在这种情况下是双精度型的 stl 向量),并写入数据文件。 对象的创建位于循环内,因此当它结束时,内存是空闲的。 就像是: for (cont=0;cont<MAX;cont++){ classSection seccion; seccion.GenerateObjects(...); while(somecondition){ seccion.evolve(); seccion.writedatatofile(); }} 所以有两个变量设置程序的计算时间,系统的大小和运行的次数。 只有运行多次的大型系统才会崩溃。 关于如何解决这个内存问题的任何想法? 谢谢, 回答1 在调试器下运行程序,以便在抛出异常后停止,您可以观察调用堆栈。 三个最可能的问题是: 堆碎片在堆上创建的对象太多(但仍然从程序中指向) 请求不合理的大内存块 回答2 valgrind 不会显示内存泄漏,因为您可能没有 valgrind 会发现的内存泄漏。 实际上,在 Java 等垃圾收集语言中可能会出现内存泄漏。 虽然内存在那里被清理
  • 在 C++11 中有零大小的 std::array 的原因吗?(Is there a reason for zero sized std::array in C++11?)
    问题 考虑下面的一段代码,它是 C++11 编译器完全可以接受的: #include <array> #include <iostream> auto main() -> int { std::array<double, 0> A; for(auto i : A) std::cout << i << std::endl; return 0; } 根据标准 § 23.3.2.8 [零大小数组]: 1数组应为特殊情况N == 0提供支持。 2在N == 0的情况下, begin() == end() ==唯一值。 的返回值 data()未指定。 3对大小为零的数组调用front()或back()的效果是不确定的。 4成员函数swap()应有一个 noexcept 规范,它等价于noexcept(true) 。 如上所示,零大小的std::array在 C++11 中是完全允许的,与零大小的数组(例如int A[0]; )相反,它们被明确禁止,但它们被一些编译器允许(例如,GCC)在未定义行为的成本中。 考虑到这种“矛盾”,我有以下问题: 为什么 C++ 委员会决定允许零大小的std::array ? 有什么有价值的用途吗? 回答1 如果您有一个通用函数,那么如果该函数因特殊参数而随机中断,那就不好了。 例如,假设您可以有一个模板函数,它采用N随机元素形成一个向量: template
  • 从 C++ 文件中删除无用的行(Removing useless lines from c++ file)
    问题 很多时候,当我在调试或重用某些代码时,文件开始获取不做任何事情的行,尽管它们可能曾经做过一些事情。 诸如向量和填充之类的东西,然后未使用,已定义但从未使用过的类/结构,以及已声明但从未使用过的函数。 我知道在很多情况下,其中一些东西并不是多余的,因为它们可能从其他文件中可见,但就我而言,没有其他文件,我的文件中只有无关代码。 虽然我明白从技术上讲,调用push_back做一些事情,因此向量本身并没有被使用,在我的情况下,它的结果没有被使用。 那么:有没有办法做到这一点,要么使用编译器(clang、gcc、VS 等),要么使用外部工具? 例子: #include<vector> using namespace std; void test() { vector<int> a; a.push_back(1); } int main() { test(); return 0; } 应该变成: int main(){return 0}; 回答1 我们的 DMS Software Reengineering Toolkit 及其 C++11 前端可用于执行此操作; 它目前没有现成的。 DMS 旨在为任意源语言提供自定义工具构建,并包含完整的解析器、名称解析器和各种流分析器来支持分析,以及根据分析结果对代码应用源到源转换的能力。 通常,您需要一个静态分析来确定是否使用每个计算(结果
  • 为什么有些语言不允许声明指针?(Why don't some languages allow declaration of pointers?)
    问题 我现在正在用 C++ 编程,我喜欢使用指针。 但似乎其他较新的语言(如 Java、C# 和 Python)不允许您显式声明指针。 换句话说,在任何这些语言中,您不能同时编写int x和int * y ,并且让x是一个值而y是一个指针。 这背后的原因是什么? 回答1 指针并不坏,它们只是容易出错。 在较新的语言中,他们找到了做同样事情的方法,但射中自己的风险更小。 不过,指针并没有错。 去爱他们吧。 对于您的示例,为什么您希望 x 和 y 都指向相同的内存? 为什么不总是叫它x? 还有一点,指针意味着您必须自己管理内存生命周期。 较新的语言更喜欢使用垃圾收集来管理内存,并且允许使用指针会使这项任务变得非常困难。 回答2 我将从我最喜欢的 Scott Meyers 名言之一开始: 当我就异常处理进行演讲时,我教给人们两件事: 指针是你的敌人,因为它们会导致auto_ptr旨在消除的各种问题。 指针是你的朋友,因为指针操作不能抛出。 然后我告诉他们祝你有美好的一天:-) 关键是指针非常有用,在用 C++ 编程时理解它们当然是必要的。 如果不了解指针,就无法了解 C++ 内存模型。 当你实现一个拥有资源的类(比如一个智能指针)时,你需要使用指针,你可以利用它们的不抛出保证来编写异常安全的资源拥有类。 但是,在编写良好的 C++ 应用程序代码中,您永远不必使用原始指针。 绝不。
  • C++大厂面试真题
    C++标准库的map和set有什么区别,如何实现的? map和set都是C++的关联容器,其底层实现都是红黑树。 map和set区别在于: map中的元素是key-value(键-值)对:关键字起到索引的作用,值则表示与索引相关联的数据;set是关键字的简单集合,set中的元素都只包含一个关键字。 set的迭代器是const的,不允许修改元素的值;map允许修改value,但不允许修改key。 其原因是map和set是根据关键字排序来保证其有序性的,如果允许修改关键字的话,那么首先需要删除该键,然后调节树平衡,再插入修改后的键值,再重新调节树平衡。这样会破坏map和set的结构,导致迭代器失效。 map支持下标操作,set不支持下标操作。 map底层为什么要用红黑树实现? 红黑树的特点:红黑树是二叉查找树,但在每个节点增加一个存储为表示节点的颜色,可以是红色或黑色,通过对任意一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长两倍。因此,它是一种弱平衡二叉树,相对于严格的平衡二叉(AVL)树来说,它的旋转次数少,所以对于查找、插入、删除较多的情况下,通常使用红黑树。 AVL是严格平衡的,频繁的插入和删除,会引起频繁的再平衡,导致效率降低;红黑树是弱平衡的,算是一种折中,插入最多旋转2次,删除最多旋转3次。所以红黑树在查找、插入、删除的复杂度都是O
  • 深入了解c++智能指针(RAII思想)
    内存泄漏 内存泄漏概念 内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。 内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。 内存泄露危害 内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死 内存泄漏分类 C/C++程序中一般我们关心两种方面的内存泄漏: 堆内存泄漏(Heap leak) 堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。系统资源泄漏 指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。 解决方式 解决方案分为两种: 1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。 智能指针的使用及其原理 RAII RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等
  • unique_ptr - 重大改进?(unique_ptr - major improvement?)
    问题 在实际的 C++ 标准中,如果不是不可能的话,创建满足以下规则的集合是很困难的: 异常安全, 廉价的内部操作(在实际的 STL 容器中:操作是副本), 自动内存管理。 为了满足 (1),集合不能存储原始指针。 为了满足 (2),集合必须存储原始指针。 为了满足 (3),集合必须按值存储对象。 结论:三个项目相互冲突。 使用shared_ptr时将不满足第 (2) 项,因为当集合需要移动元素时,它将需要进行两次调用:构造函数和析构函数。 不可能进行大规模的memcpy()的复制/移动操作。 我对所描述的问题将通过unique_ptr和std::move()解决是否正确? 使用这些工具的集合将能够满足所有 3 个条件: 当一个集合作为异常的副作用而被删除时,它将调用unique_ptr的析构函数。 没有内存泄漏。 unique_ptr不需要任何额外的空间用于引用计数器; 因此它的主体应该与包裹指针的大小完全相同, 我不确定,但看起来这允许通过使用memmove()类的操作 ( ? ) 来移动一组unique_ptrs , 即使不可能, std::move()运算符也允许移动每个unique_ptr对象,而无需进行构造函数/析构函数对调用。 unique_ptr将拥有给定内存的独占所有权。 不会出现意外的内存泄漏。 这是真的? 使用unique_ptr其他优点是什么? 回答1
  • 常量类成员、赋值运算符和 QList(Constant class members, assignment operator and QList)
    问题 如果我是正确的,请遵守并告诉我是否有更好的解决方案: 我了解具有常量成员的对象,例如int const width; 不能由编译器隐式创建的合成赋值运算符处理。 但是 QList (我想 std::list 也是如此)需要一个有效的赋值运算符。 因此,当我想使用具有常量成员和 QList 的对象时,我有三种可能性: 不要使用常量成员。 (不是解决方案) 实现我自己的赋值运算符。 使用其他不需要赋值运算符的容器 那是对的吗? 还有其他优雅的解决方案吗? 我也想知道我是否可以: (4) 强制编译器创建处理常量成员的赋值运算符! (我不明白为什么这是一个如此大的问题。为什么操作员不够聪明,无法在内部使用初始化列表?还是我遗漏了什么?) (5)告诉QList我永远不会在列表中使用赋值操作。 编辑:我从不自己分配此类的对象。 它们仅由复制构造函数或重载构造函数创建。 所以赋值运算符只需要容器而不是我自己。 EDIT2:这是我创建的赋值运算符。 我不确定它是否正确。 Cell 有一个两个参数的构造函数。 这些参数使用初始化列表设置两个常量成员。 但是该对象还包含其他变量(非 const)成员。 Cell& Cell::operator=(Cell const& other) { if (this != &other) { Cell* newCell = new Cell(other
  • 释放的堆没有被回收?(Deallocated Heap Not Being Reclaimed?)
    问题 我有一个 C++ 进程,可以摄取大块数据并将它们存储在内存中。 存储阵列包含大约 10 GB 的数据,分为 4MB 块。 当新数据到达时,它会创建一个新块,然后在旧块已满时删除旧块。 此过程每 10 到 60 秒循环一次完整的循环缓冲区。 我们在 x86_64 RH5 和 RH6 上运行,并使用 Intel 14 编译器进行编译。 我们看到了一个问题,即整个进程的内存使用量会随着时间的推移而增长,直到操作系统内存不足并最终导致机器死机。 我们一直在寻找内存泄漏并通过 TotalView 运行该过程,试图确定内存的去向,但没有看到任何报告的泄漏。 在总视图生成的堆报告中,我们看到为存储数据分配了 10GB 的内存,但我们也看到了 4GB 以上的“释放”内存。 查看堆显示,看起来我们的堆非常碎片化。 将有一大块“已分配”内存与大块“已释放”内存散布。 是否已被我的进程释放但未被操作系统回收的“解除分配”内存内存认为这可能是我们内存“泄漏”的来源是否合理? 如果是这样,我如何让操作系统回收内存? 我们是否需要重新设计流程以重用丢弃的数据块,而不是依赖操作系统为我们进行内存管理? 回答1 我猜(并希望你)你在 Linux 上(如果将你的代码移植到 Linux 是可行的,考虑一下,因为 Linux 有很好的工具来解决这些问题)。 然后: 使用 C++11(或 C++14)并了解移动语义
  • 这段代码似乎实现了C++中空引用的返回(This code appears to achieve the return of a null reference in C++)
    问题 我的 C++ 知识有点零碎。 我在工作中重新编写了一些代码。 我更改了一个函数以返回对类型的引用。 在内部,我根据传入的标识符查找对象,如果找到则返回对该对象的引用。 当然,我遇到了如果找不到对象返回什么的问题,并且在网上查看时,很多人声称在 C++ 中返回“空引用”是不可能的。 基于这个建议,我尝试了返回成功/失败布尔值的技巧,并使对象引用成为输出参数。 但是,我遇到了需要初始化作为实际参数传递的引用的障碍,当然没有办法做到这一点。 我退回到通常只返回一个指针的方法。 我问过一个同事。 他经常使用以下技巧,最新版本的 Sun 编译器和 gcc 都接受了这种技巧: MyType& someFunc(int id) { // successful case here: // ... // fail case: return *static_cast<MyType*>(0); } // Use: ... MyType& mt = somefunc(myIdNum); if (&mt) // test for "null reference" { // whatever } ... 我维护这个代码库已经有一段时间了,但我发现我没有太多时间来查找有关该语言的小细节。 我一直在翻阅我的参考书,但这本书的答案让我望而却步。 现在,几年前我有一个 C++ 课程,其中我们强调在 C++
  • 为什么要使用 new 和 delete?(Why use new and delete at all?)
    问题 我是 C++ 的新手,我想知道为什么我还要费心使用 new 和 delete? 它可能会导致问题(内存泄漏),我不明白为什么我不应该只初始化没有 new 运算符的变量。 有人可以向我解释一下吗? 很难用谷歌搜索那个特定的问题。 回答1 出于历史和效率原因,C++(和 C)内存管理是显式和手动的。 有时,您可能会在调用堆栈上进行分配(例如,通过使用 VLA 或 alloca(3))。 然而,这并不总是可能的,因为 堆栈大小是有限的(取决于平台,为几千字节或几兆字节)。 内存需求并不总是 FIFO 或 LIFO。 您确实需要分配内存,这些内存将在执行过程中很久以后被释放(或变得无用),特别是因为它可能是某个函数的结果(并且调用者 - 或其调用者 - 会释放该内存)。 你绝对应该阅读垃圾收集和动态内存分配。 在某些语言(Java、Ocaml、Haskell、Lisp 等)或系统中,提供了 GC,负责释放无用(更准确地说是无法访问)数据的内存。 另请阅读弱引用。 请注意,大多数GC需要扫描调用堆栈以查找本地指针。 请注意,拥有非常高效的垃圾收集器是可能的,但很困难(但通常不是在 C++ 中)。 对于某些程序,Ocaml(具有分代复制 GC)比具有显式内存管理的等效 C++ 代码更快。 显式管理内存有一个优势(在 C++ 中很重要),您无需为不需要的东西付费。
  • C ++-返回码异常的参数(C++ - Arguments for Exceptions over Return Codes)
    问题 我正在讨论在新的C ++项目中采用哪种方法。 由于以下原因,相对于返回码(仅在特殊情况下),我更喜欢例外: 构造函数无法提供返回码将故障路径(应该很少出现)与更干净的逻辑代码解耦在非异常情况下更快(无需检查/是否数十万次) 如果有人搞砸了返回码设置(忘记返回失败),则可能需要很长时间才能找到答案。 错误中包含的消息中提供了更好的信息。 (向我指出,返回枚举可以对错误代码执行相同的操作) 从Jare​​d Par Impossible无需代码即可忽略到专门为处理它而设计的 这些是我通过思考和Google搜索得出的观点。 我必须承认,过去几年来在C#中工作过的异常很容易引起人们的注意。 请发布使用返回码例外的其他原因。 对于那些喜欢返回码的人,我也很愿意听听您的推理。 谢谢 回答1 我认为这篇文章总结了一下。 使用异常的参数 异常将错误处理代码与常规程序流分开,从而使代码更具可读性,鲁棒性和可扩展性。 引发异常是从构造函数报告错误的唯一干净方法。 与错误代码不同,异常很难忽略。 异常很容易从深层嵌套的函数中传播出来。 异常可以是并且经常是用户定义的类型,这些类型所携带的信息远远超过错误代码。 使用类型系统将异常对象与处理程序匹配。 反对使用异常的论点 异常通过创建多个不可见的退出点来破坏代码结构,这些退出点使代码难以阅读和检查。 异常容易导致资源泄漏
  • 使用/不带有Visual Leak Detector的C ++中的内存泄漏检测(memory leak detecting in C++ with/without Visual Leak Detector)
    问题 我想检测Windows中C ++程序的内存泄漏。 我还在MSDN上阅读了有关mermoy泄漏检测的文档,并且我也开始使用Visual Leak Detector。 我对泄漏报告感到怀疑。 我期望的文件名带有行号,但是我总是报告以下文本。 它具有泄漏描述的所有组成部分(块类型,内存地址,数据等),但文件名和行号除外。 如果是真正的泄漏? 如果是,您知道为什么不报告文件/行吗? 同时,我也在看这个网址 谢谢 Detected memory leaks! Dumping objects -> {4723} normal block at 0x04AFB5B8, 8 bytes long. Data: 2C 3F 00 00 28 3F 00 00 {1476} normal block at 0x04AC3B58, 12 bytes long. Data: 00 CD CD CD EB 01 75 4C CA 3D 0B 00 Object dump complete. 回答1 我研究了跟踪内存泄漏的许多不同方法。 它们都有优点,也有缺点。 要了解它们的优缺点,我们必须了解不同的机制和要求: new,delete,malloc和free如何被截获? 一些工具使用#define重新定义new,delete,malloc和free,但这依赖于包含文件的正确顺序
  • 为什么在 C++ 中第二次调用析构函数未定义行为?(Why exactly is calling the destructor for the second time undefined behavior in C++?)
    问题 正如这个答案中提到的,简单地第二次调用析构函数已经是未定义的行为 12.4/14(3.8)。 例如: class Class { public: ~Class() {} }; // somewhere in code: { Class* object = new Class(); object->~Class(); delete object; // UB because at this point the destructor call is attempted again } 在这个例子中,类的设计方式使得析构函数可以被多次调用——不会发生像双重删除这样的事情。 内存仍然在调用delete分配 - 第一个析构函数调用不调用::operator delete()来释放内存。 例如,在 Visual C++ 9 中,上面的代码看起来有效。 即使是 UB 的 C++ 定义也不会直接禁止符合 UB 条件的东西工作。 因此,上面的代码需要破坏一些实现和/或平台细节。 为什么上面的代码会中断以及在什么条件下? 回答1 我认为您的问题针对标准背后的基本原理。 反过来想想: 定义两次调用析构函数的行为会产生工作,可能会产生大量工作。 您的示例仅表明在某些微不足道的情况下,两次调用析构函数不会有问题。 这是真的,但不是很有趣。 你没有给出一个令人信服的用例(我怀疑你能