gpt4 book ai didi

c++ - SIGABRT 在异常类的析构函数中

转载 作者:行者123 更新时间:2023-11-30 01:24:31 29 4
gpt4 key购买 nike

我为这个问题苦苦挣扎了 2 天。我有一个解决方法,但我想了解更多会发生什么。让我们开始吧。我有一个非常原始的异常类,它保存一条错误消息作为指向字符数组的指针(我知道 std::string 的利润)。我知道“三法则”,所以它看起来像:

globalexceptions.hpp

class FatalError {
public:
const char* errorMessage;
/* WARNING:
* "Rule of three". You see it below.
*/
FatalError(const char* pErrorMessage);
FatalError(const FatalError& rhs);
FatalError& operator=(const FatalError& rhs);
~FatalError();
};

globalexceptions.cpp

FatalError::FatalError(const char *pErrorMessage):
errorMessage(pErrorMessage)
{}

FatalError::FatalError(const FatalError& rhs){
char* buf = new char[strlen(rhs.errorMessage)+1];
strcpy(buf, rhs.errorMessage);
errorMessage = buf;
}

FatalError& FatalError::operator =(const FatalError& rhs){
if (this == &rhs)
return *this;
delete[] errorMessage;
char* buf = new char[strlen(rhs.errorMessage)+1];
strcpy(buf,rhs.errorMessage);
errorMessage = buf;
return *this;
}

FatalError::~FatalError(){
delete[] errorMessage;
}

但是在 throw 时:

int Config::readConfig(int argc_p, char *argv_p[])
{
if ( argc_p != 2 )
{
throw FatalError ("Sick usage. Try: <file.ini>\n");
}

我得到“SIGABRT”。

一些valgrind分析:

Invalid free() / delete / delete[] / realloc()
in FatalError::~FatalError() in globalexceptions.cpp:26
Address 0x413980 is not stack'd, malloc'd or (recently) free'd 1: operator delete[](void*) in /tmp/buildd/valgrind-3.7.0/coregrind/m_replacemalloc/vg_replace_malloc.c:490
2: FatalError::~FatalError() in <a href="file:///home/gumba/Projects/cpp/backup_helper/backup_helper-build-desktop-Qt_4_8_2_in_PATH__System__Debug/../backup_helper/globalexceptions.cpp:26" >globalexceptions.cpp:26</a>
3: /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
4: main in <a href="file:///home/gumba/Projects/cpp/backup_helper/backup_helper-build-desktop-Qt_4_8_2_in_PATH__System__Debug/../backup_helper/main.cpp:35" >main.cpp:35</a>

我做了一些研究,发现了以下信息和建议:

  • (OK:通过引用捕获) “从技术上讲,即使您通过引用捕获异常,编译器仍然使用按值传递。这是因为捕获永远不会将控制权返回给调用者,因此负责清理”
  • (OK: Have copy constructor) "被抛出的对象必须有一个可公开访问的复制构造函数。允许编译器生成复制抛出对象任意次数的代码,包括零次. 然而,即使编译器从未实际复制抛出的对象,它也必须确保异常类的复制构造函数存在并且可以访问“

根据 GDB,不会调用复制构造函数。 SIGABRT 发生在 delete[] errorMessage 上。我不明白为什么。 errorMessage 似乎已正确初始化。

SIGABRT是什么原因?

谢谢!

最佳答案

问题出在这里:

FatalError::FatalError(const char *pErrorMessage):
errorMessage(pErrorMessage)
{}

你不应该只存储那个 const char*,你应该在你的 errorMessage 成员中分配足够的大小,并将它复制到那里。否则,在析构函数中,您将删除字符串文字的地址,这将导致未定义的行为。

无论如何,你不应该在这里使用指针。只需使用 std::string,它会为您处理内存:

class FatalError {
public:
FatalError(const char *msg) : errorMessage(msg) {}
// Add an overload for std::strings
FatalError(const std::string &msg) : errorMessage(msg) {}

std::string errorMessage;
};

无需实现复制赋值运算符、复制构造函数或析构函数。

更好的解决方案是使用 std::runtime_error,它与您实现的完全相同,并且在标准库中提供:

#include <stdexcept>

int Config::readConfig(int argc_p, char *argv_p[])
{
if ( argc_p != 2 )
{
throw std::runtime_error("Sick usage. Try: <file.ini>\n");
}
// ....
}

关于c++ - SIGABRT 在异常类的析构函数中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13552529/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com