为什么"构造函数调用"不会触发任何编译器(g ++)警告?

Ale*_*op. 2 c++ multithreading compiler-warnings c++11

我实现了一个应该是线程安全的共享库.保护我std::lock_guard<std::mutex>在C++ 11标准中使用的关键区域.

错字是我省略了对象本身:

std::lock_guard<std::mutex>(getMutexObj());
Run Code Online (Sandbox Code Playgroud)

代替

std::lock_guard<std::mutex> lock_obj(getMutexObj());
Run Code Online (Sandbox Code Playgroud)

并在每个地方复制/粘贴它...不用说,当多线程应用程序开始无法预测崩溃时,我花了一段时间才导致它.

只是为了涵盖所有要点,声明getMutexObj()和互斥体本身如下:

...
mutable std::mutex  m_mutex;
...
std::mutex& getMutexObj() const
{
    return m_mutex;
}
Run Code Online (Sandbox Code Playgroud)

g++ 5.2.0使用以下警告标志编译所有代码:

WARNINGS := -pedantic \
            -Wall \
            -Wextra \
            -Werror \
            -Wconversion \
            -Woverloaded-virtual \
            -Wcast-qual \
            -Wctor-dtor-privacy \
            -Wdisabled-optimization \
            -Wuninitialized \
            -Wformat=2 \
            -Winit-self \
            -Wlogical-op \
            -Wmissing-declarations \
            -Wmissing-include-dirs \
            -Wold-style-cast \
            -Wredundant-decls \
            -Wshadow \
            -Wsign-conversion \
            -Wsign-promo \
            -Wstrict-null-sentinel \
            -Wstrict-overflow=5 \
            -Wswitch-default \
            -Wundef \
            -Wunused \
            -Wfloat-equal \
            -Wsuggest-final-methods \
            -Wsuggest-final-types \
            -Wzero-as-null-pointer-constant
Run Code Online (Sandbox Code Playgroud)

为什么编译器没有触发任何警告std::lock_guard<std::mutex>(getMutexObj());

我尝试了以下代码,看看编译器是否会抛出警告:

    std::lock_guard<std::mutex>(getMutexObj());
    int(23);
    23;
    uint16_t remove_me = 23;
Run Code Online (Sandbox Code Playgroud)

对于2,3和4号线,我收到警告但不是第1行......为什么?

<.../path/...>:32:16: error: statement has no effect [-Werror=unused-value]
         int(23);
                ^
<.../path/...>:33:11: error: statement has no effect [-Werror=unused-value]
         23;
           ^
<.../path/...>:34:18: error: unused variable 'remove_me' [-Werror=unused-variable]
         uint16_t remove_me = 23;
                  ^
cc1plus: all warnings being treated as errors
Run Code Online (Sandbox Code Playgroud)

EDIT1

我注意到这个问题有点令人困惑,因为几乎所有答案都与之相关

对于2,3和4号线,我收到警告但不是第1行......为什么?

然而,真正的问题是:

为什么编译器没有触发任何警告std::lock_guard<std::mutex>(getMutexObj());

是否有任何开关使编译器警告这样的代码?

EDIT2

正如他在评论中提到的cpplearner,std::lock_guard<std::mutex>(getMutexObj());被视为函数声明的函数声明getMutexObj返回std::lock_guard<std::mutex>.

我查看了反汇编,看到了如果std::lock_guard<std::mutex>(getMutexObj());没有相关的操作码.

但是当我改成它时

std::lock_guard<std::mutex>{getMutexObj()};
Run Code Online (Sandbox Code Playgroud)

并查看了反汇编,它被编译为临时对象创建,但再次没有任何警告.

Bo *_*son 7

23;消息"错误:语句无效"不同,创建未命名的临时lock_guard 确实具有锁定和解锁互斥锁的效果.

这具有其他线程可见的内存屏障的副作用.

  • @Alex - 考虑你打算写的代码`std :: lock_guard <std :: mutex> lock_obj(getMutexObj());`.为什么编译器没有为此发出未使用的变量警告?`lock_obj`不在函数的任何其他地方使用.因为对象的构造和破坏是有用的.即使没有名字也可能. (3认同)

Jon*_*ely 5

std::lock_guard<std::mutex>(getMutexObj());
Run Code Online (Sandbox Code Playgroud)

这实际上应该给出一个错误,因为它声明了一个被调用的函数getMutexObj但是已经使用不同的返回类型声明了(并且你不能在返回类型上重载).这是一个GCC错误,我已将其报告为错误69855.

这种情况不同:

std::lock_guard<std::mutex>{getMutexObj()};
Run Code Online (Sandbox Code Playgroud)

确实创建了一个临时的,但这里没有警告,因为编译器不是魔术.

警告被添加到编译器以捕获常见错误,但有人必须实际执行代码来检查它,并发出警告.这不仅仅发生在魔法或仙女的到来,并且在没有人看的时候在晚上改进了编译器.

在这种情况下,编译器会看到您正在创建一个临时变量,它具有副作用(它写入全局内存位置,互斥锁并发出内存障碍).编译器不知道那些副作用并不完全是你想要做的,因为它不是魔术.

如果编译器在这里发出警告会很好,有人确实为GCC写了一个补丁来警告这个,请参阅错误36587,但正如我在该错误报告中指出的那样,它也会警告有效的代码.如果编译器在每次创建具有副作用的临时变量时发出警告,那将是很糟糕的.这是使用类似语法的有效方案:

std::ofstream( "./lockfile" );
Run Code Online (Sandbox Code Playgroud)

这将打开一个ofstream具有特定名称的文件,如果该文件尚不存在,则会创建该文件.编译器不应该警告这一点,因为它完全有效.

因此,为了警告您的示例,而不是其他类似的代码片段,需要一些额外的信息来告诉编译器该lock_guard类型永远不应该以这种方式使用.这意味着以lock_guard某种方式注释并教导编译器识别该注释.同样,仙女不会来做这项工作,所以它没有发生,因为它没有被优先考虑,没有人写过补丁.

GCC支持warn_unused构造函数的属性,参见bug 55203,但这无济于事,lock_guard因为正确使用类意味着它总是"未使用"(在构造之后你永远不会引用它).对于这种情况,需要实现不同的属性和警告.