gpt4 book ai didi

c++ - 当网络边缘的构造函数抛出时避免 SIGTRAP

转载 作者:太空宇宙 更新时间:2023-11-03 10:22:51 26 4
gpt4 key购买 nike

背景

我有一个类似设置节点和边的网络。节点和边都需要是类,在本例中为 NodeArcas in this question .在我的实际设置中,我正在处理 Node 和 Arc 的相当多的子类。对于内存管理,我使用 this answer to the question above .

问题

当构造函数抛出异常时,Windows 上的 Visual Studio 和 g++ with MinGW 无法捕获它,而是在没有错误处理的情况下退出(g++/MinGW 报告 SIGTRAP 信号),而 Linux 上的 g++ 和 clang++ 正确处理异常。如果 Arc 无一异常(exception)地创建 Arc(n1, n2, false),则所有编译器都可以正常工作。在所有情况下,都没有相关的编译器警告(使用/W4 resp.-Wall)有人可以解释一下,为什么这在 Windows 上不起作用?或者甚至提供解决方法?

代码

#include <iostream>
#include <stdexcept>
#include <vector>
#include <memory>

struct Node;
struct Arc {
Node *left,*right;
private:
// shared pointer to self, manages the lifetime.
std::shared_ptr<Arc> skyhook{this};
public:
// c'tor of Arc, registers Arc with its nodes (as weak pointers of skyhook)
explicit Arc(Node* a_, Node* b_, bool throw_exc);
// resets skyhook to kill it self
void free() {
std::cout << " Arc::free();\n" << std::flush;
skyhook.reset();
}
virtual ~Arc() {
std::cout << " Arc::~Arc();\n" << std::flush;
}
};

struct Node {
explicit Node() {
std::cout << " Node::Node()\n" << std::flush;
}
std::vector<std::weak_ptr<Arc> > arcs;
~Node() {
std::cout << " Node::~Node();\n" << std::flush;
for(const auto &w : arcs) {
if(const auto a=w.lock()) {
a->free();
}
}
}
};

Arc::Arc(Node *a_, Node *b_, bool throw_exc) : left(a_), right(b_) {
std::cout << " Arc::Arc()\n" << std::flush;
if (throw_exc) {
throw std::runtime_error("throw in Arc::Arc(...)");
}
a_->arcs.push_back(skyhook);
b_->arcs.push_back(skyhook);

}

int main(int argc, char* argv[]) {
std::cout << "n1=new Node()\n" << std::flush;
Node *n1 = new Node();
std::cout << "n2=new Node()\n" << std::flush;
Node *n2 = new Node();
std::cout << "try a=new Arc()\n" << std::flush;
try {
Arc *a = new Arc(n1, n2, true);
} catch (const std::runtime_error &e) {
std::cout << "Failed to build Arc: " << e.what() << "\n" << std::flush;
}
std::cout << "delete n1\n" << std::flush;
delete n1;
std::cout << "delete n2\n" << std::flush;
delete n2;

}

输出

这是我在 Linux 和 Windows 上都得到的结果

n1=new Node()
Node::Node()
n2=new Node()
Node::Node()
try a=new Arc()
Arc::Arc()

在 Linux 上使用 g++(7.4.0 和 8.3.0)或 clang++(6.0.0)...

它按预期工作:

  Arc::~Arc();
Failed to build Arc: throw in Arc::Arc(...)
delete n1
Node::~Node();
delete n2
Node::~Node();

使用 VC++ (2017) ...

它坏了

Arc::~Arc()

并且运行以退出代码 -1073740940 (0xC0000374) 终止

使用 g++ (9.1.0) MinGW 7.0

它坏了,但报告了信号

Signal: SIGTRAP (Trace/breakpoint trap)
Arc::~Arc();

并以退出代码 1 结束

最佳答案

tl;dr:继承自 std::enable_shared_from_this并使用 weak_from_this() .


考虑以下结构,它与您的结构相似 ( https://godbolt.org/z/vHh3ME ):

struct thing
{
std::shared_ptr<thing> self{this};

thing()
{
throw std::exception();
}
};

对象的状态是什么*thisself在抛出异常的那一刻,哪些析构函数将作为堆栈展开的一部分执行?对象本身尚未完成构建,因此 ~thing()不会(也不能)被执行。另一方面,self 完全构造的(成员在进入构造函数体之前被初始化)。因此,~std::shared_ptr<thing>() 执行,这将调用~thing()在未完全构建的对象上。

继承自 std::enable_shared_from_this假设没有实际的 shared_ptr 则不会出现此问题s 是在构造函数完成执行和/或抛出之前创建的( weak_from_this() 在这里是你的 friend ),因为它只包含一个 std::weak_ptr ( https://godbolt.org/z/TGiw2Z );您的 shared_ptr 的变体也没有在构造函数 ( https://godbolt.org/z/0MkwUa ) 的末尾初始化,但这在您的案例中并不是微不足道的,因为您在构造函数中给出了共享/弱指针。

话虽如此,您仍然有所有权问题。没有人真正拥有你的 Arc ;对它的唯一外部引用是 weak_ptr

关于c++ - 当网络边缘的构造函数抛出时避免 SIGTRAP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56750390/

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