【问题标题】:Is there a compile warning about this use of std::move?是否有关于这种使用 std::move 的编译警告?
【发布时间】:2020-06-07 21:25:32
【问题描述】:

以下程序显示了std::move() 的两个有问题(但在技术上有效)的用法。是否可以使用 LLVM 获得关于这些的编译警告?我注意到在std::move 是多余的一些其他上下文中存在诊断。

我用 bcc32c 版本 5.0.2(基于 LLVM 5.0.2)编译了它,没有收到任何警告。

#include <vector>

int main() {
    const std::vector<int> a = {1, 2, 3};
    std::vector<int> b = {3, 4, 5};

    std::vector<int> c = std::move(a); // std::move from const

    std::vector<int> d = std::move(b);

    std::vector<int> e = b; // used after std::move
}

【问题讨论】:

  • 第二种情况很难诊断。类可以指定移动后的状态是明确定义的; std::unique_ptr&lt;T&gt; 就是一个例子。
  • 第二种情况也为std::vector&lt;T&gt;定义好了。
  • Visual Studio 中的代码分析器(但使用 clang-cl)发现了第二种情况:警告 G8547E8E7:已复制“std::vector”类型的对象“b”[ clang-analyzer-cplusplus.Move] std::vector e = b; // 在 std::move 之后使用
  • @juanchopanza 定义明确,但可能是无意的。这就是我想要检测它的原因。
  • 有趣的问题,我从来没想过。我做了一个MCVE on coliru来说明效果。

标签: c++ clang llvm c++builder


【解决方案1】:

clang-tidy 的 bugprone-use-after-move 检查器支持这种诊断:

bugprone-use-after-move

如果对象在移动后被使用,则发出警告,例如:

std::string str = "Hello, world!\n";
std::vector<std::string> messages;
messages.emplace_back(std::move(str));
std::cout << str;

最后一行会触发一个警告说 str 被使用后 被移动了。

[...]

使用

任何不是重新初始化(见下文)的移动变量的出现都被视为使用。

[...]

如果移动后出现多次使用,则仅标记其中的第一个。

【讨论】:

    【解决方案2】:

    clang-tidy 有一个 performance-move-const-arg 检查,会发出警告:

    1. 如果使用常量参数调用 std::move(),
    2. 如果 std::move() 使用可平凡复制类型的参数调用,
    3. 如果 std::move() 的结果作为 const 引用参数传递。

    在所有这三种情况下,检查都会建议删除 std::move() 的修复。

    下面的例子:

    const string s;
    return std::move(s);  // Warning: std::move of the const variable has no effect
    
    int x;
    return std::move(x);  // Warning: std::move of the variable of a trivially-copyable type has no effect
    
    void f(const string &s);
    string s;
    f(std::move(s));      // Warning: passing result of std::move as a const reference argument; no move will actually happen
    

    【讨论】:

    • 您好,您能解释一下为什么当 x 是定义为 POD 类型的结构时,我在第二次收到相同的警告吗?例如。 struct {int i, int j} x;。我仍然希望它作为右值传递,那么为什么在这种情况下我不需要std::move(x)?我如何确定它是右值?
    • 更糟糕的是,如果我在将std::move 作为左值传递时不指定它,则会收到编译器警告。显然这是这个clang-tidy检查reviews.llvm.org/D107450的一个已知问题!! :o
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-23
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 2022-06-27
    • 2023-01-07
    相关资源
    最近更新 更多