当使用已在其他地方进行std :: move'ed的变量时出现错误,或者至少是警告

问题描述 投票:8回答:4

此:

void foo(int &&r) {
  std::cout << r << std::endl;
}

int main() {
  int i = 2;
  foo(std::move(i));
  i = 3; //no warning. any way to get some warnings here?
  return 0;
}

如果移动变量后我不小心使用了变量,没有办法告诉编译器给我一个错误(或警告)吗?我认为这将非常方便。很多时候,我发现自己将变量移动到其他地方,但是后来我不得不非常小心地避免以后再使用它们。现在这还没有引起任何问题,但是谁知道呢...最好还是安全的!

也许存在一些预处理器的技巧(或相当广泛使用的编译器扩展)可以做到这一点?


更实际的示例:

struct HugeStorage {
  std::vector<double> m_vec;
  HugeStorage(std::vector<double> vec) : m_vec(std::move(vec)) { }
};

struct SmallStorage {
  std::vector<double> m_vec;
  SmallStorage(std::vector<double> vec) : m_vec(std::move(vec)) { }
};

std::vector<double> vec_from_data_source() {
  return std::vector<double>(); //only example!!
}

int main() {
  std::vector<double> vec = vec_from_data_source();
  if (vec.size() > 10000)
  {
    HugeStorage storage(std::move(vec));
    //do some things, but I gotta be careful I don't do anything to vec
  }
  else
  {
    SmallStorage storage(std::move(vec));
    //do some things, but I gotta be careful I don't do anything to vec
  }
  return 0;
}
c++ c++11 move-semantics
4个回答
10
投票

如果移动变量后我不小心使用了变量,是否没有办法告诉编译器给我一个错误(或警告)?

答案是“没有,没有办法”(至少就我所知,目前没有可用的编译器提供这样的选项,并且有充分的理由-见下文)。

即使完全有可能,在这种情况下,为什么还要给出警告,甚至更糟的错误?首先,从整数移动与复制整数没有什么不同。

第二,对于most类型,分配该类型的移出对象是完全合法的操作;对于诸如int之类的基本类型总是如此,并且对于std::vector也确实如此,尽管其他类型可能并非如此。

[通常,分配移出的对象是否合法取决于该类型的移动操作的特定后置条件以及赋值运算符的先决条件(标准库类型的赋值运算符没有前置条件)。这是编译器通常无法检查的内容。

因此,如果您要:

  1. 从对象移动,移动分配或移动构造函数将对象从其移动到未指定状态std::vector就是这种情况),然后;
  2. 在该对象的状态上使用前提条件调用任何函数(并且对于分配给std::vector的情况为not;]

那肯定是不好的。另一方面,编译器无法执行程序的语义分析并确定是否是这种情况:

A x, y;
...
if (complicatedCondition())
{
    y = move(x);
} 

foo(x); // Did I move from x? And if so, is it safe to call foo()?

此外,别忘了C ++的理念是为您提供功能和(通常)为您提供设计指导,但是,如果您确实想做到这一点,请“让您投篮”。

are危险的,甚至是毫无意义的事情,您都可以在C ++中完成(如果您尝试两次delete相同的指针两次,编译器是否会向您发出警告或错误?),但是语言本身在您确实非常了解自己在做什么的假设下,不会阻止您执行这些操作。


5
投票
//do some things, but I gotta be careful I don't do anything to vec

说明:您需要注意不要对需要先决条件的vec做任何事情。您可以使用vec执行不是需要任何前提条件的任何操作。例如,您可以为vec分配一个新值。您可以呼叫vec.clear()。您可以呼叫vec.size()。但是不要调用vec.pop_back(),因为该成员函数具有先决条件。


0
投票

我认为您正在尝试使用move代替变量作用域。

int main() 
{
  {
    int i = 2;
    foo(std::move(i));
  }
  i = 3; // error!
  return 0;
}

0
投票

c整洁可以给您这样的警告(有关详细信息,请参见https://clang.llvm.org/extra/clang-tidy/checks/bugprone-use-after-move.html

© www.soinside.com 2019 - 2024. All rights reserved.