我有一些 C 代码,几年前被迅速“转换”为 C++ 代码,现在我正在维护。在不同的操作系统上运行它并使用不同的编译器构建时,我注意到一些奇怪的行为,并且可以使用一些帮助来诊断我最近解决的一些问题。
代码在以下系统上运行没有问题:
- Ubuntu 14.04.2 LTS x64
- 海湾合作委员会 4.8.4
将其移植到以下系统后,事情就变糟了:
- OSX“El Capitan”
- Apple LLVM 版本 7.3.0 (clang-703.0.29)
违规代码围绕以下结构展开:
struct blk_data {
int i;
int s;
boost::mutex protectionMutex;
};
有一段代码,其中通过 malloc()
创建了此 POD 的动态实例(普通旧数据,无自定义方法或构造函数等):
struct blk_data* pData = (blk_data*)malloc(16 * sizeof(struct blk_data));
if ( pData )
//...
请忽略我正在转换 malloc()
的结果这一事实。如果我不这样做,编译器会标记错误。
稍后在代码中,我调用:
boost::unique_lock<boost::mutex> tempLock(pData->protectionMutex);
对于带有 GCC 的 Linux,没有问题。对于 OSX 和 Clang,程序会出错,指出最终传递给 pthread_mutex_lock()
的互斥锁地址无效。最终,我能够通过以下方式解决此问题:
- 使用
new
代替malloc()
。 - 设置
${CXXFLAGS} += -std=c++11
第二个会出现类似问题的情况是使用 new
的代码块,然后 memset
结构。据我了解,如果使用 POD struct
,这是安全的。
为什么这段代码在 GCC/Linux 上构建和运行良好,但它构建了,但不运行;在 Clang/OSX 上?如果 struct
包含 RAII 样式的成员,它是否不再算作 POD struct
,或者我是否一直违反了 C++ 标准的一部分(即:未定义的行为) ?或者这是在 Clang 与 GCC 中进行更严格检查的情况。
谢谢。
最佳答案
虽然我不确定 boost::mutex
是否是 POD,但是 malloc
只分配内存但不初始化对象,这使得 protectionMutex
未初始化。
new
确保调用 boost::mutex
的默认构造函数,从而初始化 protectionMutex
。
[更新] 检查 boost mutex 的 header file ,它在内部使用了一个指针:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
所以malloc
肯定不会初始化指针,而new
会。
但我真的不知道为什么 GCC 可以工作...
关于c++ - 使用 Clang 而不是 GCC 构建(有问题的)示例时内存损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36746523/