- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个类似设置节点和边的网络。节点和边都需要是类,在本例中为 Node
或 Arc
,as 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()
它按预期工作:
Arc::~Arc();
Failed to build Arc: throw in Arc::Arc(...)
delete n1
Node::~Node();
delete n2
Node::~Node();
它坏了
Arc::~Arc()
并且运行以退出代码 -1073740940 (0xC0000374) 终止
它坏了,但报告了信号
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();
}
};
对象的状态是什么*this
和 self
在抛出异常的那一刻,哪些析构函数将作为堆栈展开的一部分执行?对象本身尚未完成构建,因此 ~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/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!