我发现自己编写这样的代码来实现异常安全的代码:
Container* container = [Container new];
@try {
while(someCondition) {
ElementType* value = [someObject createObjectFromStorage];
[container add:value]; // container retains object
[value release];
}
[_container release];
_container = [container retain];
} @finally {
[container release];
}
Run Code Online (Sandbox Code Playgroud)
在Objective-C中还有其他一些更简洁的模式吗?
我正在尝试找到一个在线参考,以查看几个标准容器的异常安全性.
在这种情况下 std::vector,它是否保持push_back调用之前的状态?我认为向量的所有对象仍然有效(没有调用析构函数).std::vectorpush_back抛出std::bad_alloc异常后提供什么保证?
有效的现代 C++ 第 146 页:
void processWidget(std::shared_ptr<Widget> spw, int priority);
void cusDel(Widget *ptr);//a custom deleter
Run Code Online (Sandbox Code Playgroud)
这是 C++17 之前的不安全调用:
processWidget(std::shared_ptr<Wdiget>(new Widget, cusDel), computePriority());
Run Code Online (Sandbox Code Playgroud)
它曾经是不安全的,因为computePriority 可以new Widget在std::share_ptr构造函数之后但之前调用,如果computePriority产生异常,动态allcoated Widget 将被泄漏。因此你可以这样做:
std::shared_ptr<Widget> spw(new Widget, cusDel);
processWidget(spw, computePriority());
Run Code Online (Sandbox Code Playgroud)
现在这将在 shared_ptr 上添加一个复制构造函数操作。所以你也可以这样做:
std::shared_ptr<Widget> spw(new Widget, cusDel);
processWidget(std::move(spw), computePriority());
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,以下代码是否仍然能够在 C++17 中泄漏内存?
processWidget(std::shared_ptr<Wdiget>(new Widget, cusDel), computePriority());
Run Code Online (Sandbox Code Playgroud)
我读过这个和这个,但我仍然不能确定,相信std::shared_ptr<Wdiget>(new Widget, cusDel)和computePriority()被调用processWidget前两者测序,但是我觉得computePriority()还是可以抛出后异常new之前shared_ptr采取新创建的对象的所有权。
是f()异常安全的调用吗?
inline std::auto_ptr<C> auto_new() {
return std::auto_ptr<C>(new C());
}
void f(std::auto_ptr<C> p1,
std::auto_ptr<C> p2);
// ...
{
f(auto_new(), auto_new());
}
Run Code Online (Sandbox Code Playgroud)
换句话说,auto_new()如果两个函数是内联的,那么当涉及到第一个和第二个函数调用的原子性时,它会有什么不同吗?
我在C ++规范(cplusplus.com)上徘徊,发现没有任何关于std :: unordered_map异常安全的信息
所以基本上如果我写
map["foo"]=5;
Run Code Online (Sandbox Code Playgroud)
并且由于内存或bad_alloc不足而引发异常,我可以假设我的地图是什么?
我有一些看起来有点像这样的代码:
void writeToStream( std::ostream & outputStream )
{
MyXmlWriter xmlWriter{ outputStream };
xmlWriter.addNode();
xmlWriter.addNode();
xmlWriter.close(); // should this be called in `MyXmlWriter` destructor?
}
Run Code Online (Sandbox Code Playgroud)
close函数会写一些xml关闭标记,以便正确解析文件.构造函数编写xml文件的标头.人们可以考虑xmlWriter.close();清理代码.C++的常见建议是将清理代码放入析构函数中.这样你就永远不会忘记清理干净.但是,在我们的例子中,清理代码可能会抛出.(想象一下,file可能启用了异常,对文件的写入可能会失败.)因此,如果close()在析构函数中调用该函数,那么它应该包装在try-catch块中,该块会占用抛出的所有异常:
MyXmlWriter::~MyXmlWriter()
{
try
{
close();
}
catch (...)
{
}
}
Run Code Online (Sandbox Code Playgroud)
但是,在这种情况下,呼叫者不会收到有关任何错误的通知.该函数writeToStream()可能无法将关闭的xml标记写入文件,而调用者不知道它.在这种情况下,最佳做法是什么?
我一直在阅读GOTW102,并且想知道为什么make_unique比其他情况更安全,或者为什么f(new T(...))比例更安全f(new T1(...), new T2(...)).
make_unique博客的实施内容如下:
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}
Run Code Online (Sandbox Code Playgroud)
现在我想知道是否f(new T(...))一般异常安全(无泄漏),或者如果它只是异常安全的情况下,make_unique因为增加的知识,建设者std::unique_ptr不扔?(T根据我的理解,如果新建的话会被泄露.
这是libstdc++ 中 new 运算符的实现:
_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
void *p;
/* malloc (0) is unpredictable; avoid it. */
if (__builtin_expect (sz == 0, false))
sz = 1;
while ((p = malloc (sz)) == 0)
{
new_handler handler = std::get_new_handler ();
if (! handler)
_GLIBCXX_THROW_OR_ABORT(bad_alloc());
handler ();
}
return p;
}
Run Code Online (Sandbox Code Playgroud)
谁保证构造函数中的异常会释放分配的内存?
更新:感谢评论员 - 实际上我的意思是新表达式的异常安全。
我在InitOnceExecuteOnce WinAPI函数上有一个异常安全问题.每当从回调函数抛出异常时,就会发生死锁.回调返回boolean标志告诉调用者数据是否成功初始化,但是如果我返回false,我将无法重新抛出异常,这不好.我尝试过这样解决问题.
try
{
InitOnceExecuteOnce(&flag, init_once_handler, &arguments, 0);
} catch (...)
{
InitOnceInitialize(&flag);
throw;
}
Run Code Online (Sandbox Code Playgroud)
每当我从函数中捕获异常时,我再次初始化结构并重新抛出异常,因此其他线程将发现数据未初始化,因为标志处于初始状态.但是,它有时也会死锁,可能是因为其他线程在第一个捕获异常并再次初始化标志之前开始等待同步对象.这个问题有什么解决方案吗?
提前致谢.
如果在将对象移至std :: vector时内存分配失败,并且抛出bad_alloc,std :: vector是否保证从对象移出的对象不变/仍然有效?
例如:
std::string str = "Hello, World!";
std::vector<std::string> vec;
vec.emplace_back(std::move(str));
/* Is str still valid and unaltered if the previous line throws? */
Run Code Online (Sandbox Code Playgroud) exception-safety ×10
c++ ×8
c++11 ×1
c++14 ×1
c++17 ×1
destructor ×1
exception ×1
file-io ×1
objective-c ×1
raii ×1
std ×1
stdvector ×1
vector ×1
winapi ×1