我正在尝试编写一个单元测试来检测对我的类的 lock() 功能的无效使用。为此,我想使用析构函数并从那里抛出异常。不幸的是,g++ 没有捕获异常,而是决定调用 std::terminate()。
类有一个非常简化的版本:
class A
{
public:
A() : f_lock(0) {}
~A() { if(f_lock) throw my_exception("still locked"); }
lock() { ++f_lock; }
unlock() { --f_lock; }
private:
int f_lock;
};
有一个有效的测试:
A *a = new A;
a->lock();
...
a->unlock();
delete a;
我正在尝试编写无效测试:
A *a = new A;
a->lock();
...
bool success = false;
try
{
delete a;
}
catch(my_exception const&)
{
success = true;
}
catch(...)
{
// anything else is a failure
}
if(!success)
{
// test failed...
CPPUNIT_ASSERT(!"test failed");
}
现在,delete 调用 std::terminate(),即使在另一个异常处于事件状态时未调用 throw。 (即 std::uncaught_exception() 为 false。)而且我显然捕获了所有异常!
是我做错了什么,还是 g++ 总是在析构函数中做错事?
更新:
dyp 在下面评论中的回答有效!以下不直接调用 std::terminate():
~A() noexcept(false) { throw ...; }
还有关于为什么你不想在析构函数中抛出的引用,这个页面非常好;
为了澄清,这里有完整版的析构函数。正如我们所看到的,我首先发布了一条消息(它通常会出现在您的控制台中,也可能会出现在日志中)。其次,我确保我们还没有管理异常。最后,我抛出一个名为 exception_exit 的异常,预计会强制执行 terminate(),尽管在 GUI 应用程序中您可能想要显示一个 MessageBox某种方式让用户知道发生了什么事(因为您可以捕获消息,您可以将其显示给用户)然后强制关闭应用程序。
Node::~Node() noexcept(false)
{
if(f_lock > 0)
{
// Argh! A throw in a destructor... Yet this is a fatal
// error and it should never ever happen except in our
// unit tests to verify that it does catch such a bug
Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_NOT_ALLOWED);
msg << "a node got deleted while still locked.";
// for security reasons, we do not try to throw another
// exception if the system is already trying to process
// an existing exception
if(std::uncaught_exception())
{
// still we cannot continue...
std::abort();
}
throw exception_exit(1, "a node got deleted while still locked.");
}
}
还有一个细节,你应该使用NodeLock对象来管理f_lock标志。这是异常安全的,因为它使用 RAII(即作用域锁)。但是,此时我不想强制用户使用 NodeLock 来锁定/解锁节点,因此在析构函数中进行了此测试。
最佳答案
在 C++11 中,添加了 noexcept 关键字。这可以用于函数异常规范:
noexcept(true) 与 throw() 相同,即此函数 terminates if anything are throwednoexcept(false) 表示函数可能会抛出任何东西对于大多数函数,它们没有异常规范,除非您给它们一个。没有异常规范 的函数可能会抛出任何东西。
虽然在 C++11 [class.dtor]/3 中发现了析构函数的特殊情况:
A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration (15.4).
引用的规则 15.4 指出隐式声明的特殊成员函数总是有一个异常规范。规范由以下规则确定,[except.spec]/14:
An implicitly declared special member function (Clause 12) shall have an exception-specification. If
fis an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-idTif and only ifTis allowed by the exception-specification of a function directly invoked byf’s implicit definition;fshall allow all exceptions if any function it directly invokes allows all exceptions, andfshall allow no exceptions if every function it directly invokes allows no exceptions.
本子句中的“它直接调用的函数”是指任何成员变量或基类的析构函数(递归应用)。如果没有这个函数,那么这个函数不允许有异常,所以默认是noexcept(true)。
我们可以这样总结上述引用中与您的代码相关的部分:
noexcept(true) 或等效的析构函数;那么这个类的析构函数默认为noexcept(true)。 因此,将析构函数更改为具有 noexcept(false) 将重现 C++03 的行为。
在 C++03 中,这些都没有出现,您的析构函数将默认允许所有异常。我不确定为什么要在 C++11 中进行此更改,但这可能是因为除非您真的知道自己在做什么,否则从析构函数中抛出是个坏主意。
关于c++ - 为什么在我的析构函数中抛出时总是得到 "terminate called after throwing an instance of..."?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26331364/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput