关于利用C/C++ 利用编译器RAII机制,在多种编译器及跨平台下得兼容性问题。
在C/C++ 之中,我们常常利用RAII机制,来处理某个临时块得初始、及利用编译器自动析构,但这可能存在一定的致命性风险,如果你没有遇到,只是你没有过多的进行了解,挨得毒打太小,导致的。
举几个小例子:
以利用 std::lock_guard<std::mutex> 为例;
定义:
typedef std::mutex SynchronizedObject;
typedef std::lock_guard<SynchronizedObject> SynchronizedObjectScope;
例一:
bool IForwarding::TryRemove(boost::asio::ip::tcp::socket* socket, bool disposing) noexcept {
std::shared_ptr<boost::asio::ip::tcp::socket> ptr;
IForwarding::SynchronizedObjectScope scope(syncobj_);
return Dictionary::TryRemove(sockets_, socket, ptr);
}
上述例子,在不同得编译器根平台上面会存在不同得效果,取决于编译器得实现,按照人们显示理解:
在 Dictionary::TryRemove 函数执行完毕以后,其键值通过FAR指针反弹到调用方PTR变量之中。
在调用方 TryRemove 函数执行结束后,先执行 SynchronizedObjectScope 的析构,
在执行 std::shared_ptr 的析构函数,在很多编译器之中是这样,但在一些编译器之中,
它可能不是这样执行的,这就带来了一些不可控制的因素,所以看上去,我们需要例二:
bool IForwarding::TryRemove(boost::asio::ip::tcp::socket* socket, bool disposing) noexcept {
std::shared_ptr<boost::asio::ip::tcp::socket> ptr; {
IForwarding::SynchronizedObjectScope scope(syncobj_);
return Dictionary::TryRemove(sockets_, socket, ptr);
}
}
其实这种在所有的编译器当中,都是可以正确执行的,看上去已经完全没有问题了,但当人们启用编译器 -O3、-OX 编译器最大优化时,它在一些编译器及平台上面仍旧会出现问题,所以,这个时候,我们需要例三:
bool IForwarding::TryRemove(boost::asio::ip::tcp::socket* socket, bool disposing) noexcept {
std::shared_ptr<boost::asio::ip::tcp::socket> ptr;
do {
IForwarding::SynchronizedObjectScope scope(syncobj_);
return Dictionary::TryRemove(sockets_, socket, ptr);
} while (false);
}
上述的代码,在绝大多数编译器及平台上面都可以确保流程跟我们预期的一致性,但仍旧不能保证在优化之后会像例二一般,出现问题,虽然这段代码的编写方式,比例子二在更多的编译器、及平台上面有保证,所以我们需要例子四。
例子四点一:
bool IForwarding::TryRemove(boost::asio::ip::tcp::socket* socket, bool disposing) noexcept {
std::shared_ptr<boost::asio::ip::tcp::socket> ptr;
for (;;) {
IForwarding::SynchronizedObjectScope scope(syncobj_);
return Dictionary::TryRemove(sockets_, socket, ptr);
}
}
例子四点二:
bool IForwarding::TryRemove(boost::asio::ip::tcp::socket* socket, bool disposing) noexcept {
std::shared_ptr<boost::asio::ip::tcp::socket> ptr;
bool result = false;
for (;;) {
IForwarding::SynchronizedObjectScope scope(syncobj_);
result = Dictionary::TryRemove(sockets_, socket, ptr);
break;
}
return result;
}
以上无论那种形式,都可以在所有的C/C++编译器及平台上面,按照我们预期流程正确执行,在C/C++之中编译器优化。
{ 代码 } ,do { 代码 } while (0, false); 这样的形式,都可能被优化错误,因为在开编译器O3/OX优化时,它们会被编译器预处理,进行栅格退化,退化的结果是不可控制的。
在C/C++ 之中,for (;;) 、while (1) ;;; 是不会被退化的,因为编译器没有这样的优化策略,当然,如果你通过禁用编译器优化的目的,也可以解决问题,只不过这可能不符合,我们的能效预期。
原文地址:https://blog.csdn.net/liulilittle/article/details/140289076
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!