Фон
У меня есть сетевая настройка с узлами и ребрами. И узлы, и ребра должны быть классами, в этом случае Node
или Arc
, , как в этом вопросе . В моей реальной работе я имею дело с множеством подклассов как Node, так и Arc. Для управления памятью я использую этот ответ на вопрос выше .
Задача
Когда конструктор выдает исключение, Visual Studio и g ++ с MinGW в Windows не могут его перехватить, но завершают работу без обработки ошибок (g ++ / MinGW сообщает о сигнале SIGTRAP), в то время как g ++ и clang ++ в Linux обрабатывают исключение правильно. Если Arc создана без исключения Arc(n1, n2, false)
, все компиляторы работают нормально. Во всех случаях нет соответствующих предупреждений компилятора (с использованием / W4 или соответственно -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()
С g ++ (7.4.0 и 8.3.0) или clang ++ (6.0.0) в Linux ...
работает как положено:
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