使用已在其他位置std :: move'ed的变量时出错或至少是警告

use*_*453 8 c++ move-semantics c++11

这个:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

也许有一些预处理器技巧(或相当广泛可用的编译器扩展)存在来做这些事情?


更现实的例子:

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;
}
Run Code Online (Sandbox Code Playgroud)

And*_*owl 10

如果我在移动变量后意外使用变量,是否无法告诉编译器给我一个错误(或警告)?

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

即使这是可能的,为什么你会期望在这种情况下发出警告,甚至更糟糕的错误呢?首先,从整数移动与复制它没有任何不同.

其次,对于大多数类型,分配该类型的移动对象是完全合法的操作; 对于基本类型来说int,这总是如此,并且它确实是正确的std::vector,尽管它可能不适用于其他类型.

通常,分配移动对象是否合法取决于该类型的移动操作的特定后置条件以及赋值运算符的前提条件(标准库类型的赋值运算符没有前提条件)左手边的论点).这是编译器在一般情况下无法检查的内容.

因此,如果你是:

  1. 从移动赋值或移动构造函数将移动的对象放置在未指定状态(对于这种情况std::vector)的对象移动,然后;
  2. 调用具有该对象状态的前提条件的任何函数(并且不是指定给它的情况std::vector);

那肯定会很糟糕.另一方面,编译器没有办法对程序执行语义分析,并找出是否是这种情况:

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

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

此外,不要忘记C++的哲学是给你力量和(最常见的)设计指导,但如果你真的想要这样做,"让你射击你的脚".

这里危险的,甚至是毫无意义的事情,你可以在C做++(将你的编译器给你一个警告或错误,如果你试图delete同一指针两次?),但语言本身不会阻止你做他们,假设你真的,真的知道你在做什么.

  • @DavidRodríguez-dribeas:17.6.5.15/p1保证所有从std :: lib类型移动的都将处于有效但未指定的状态.这意味着除非类型在赋值语句的lhs上有前提条件,否则即使在移动之后也可以将其赋值.请注意,此一揽子声明适用于std-lib中的类型,而不适用于一般类型.我不知道任何std :: type有一个前提条件被分配给. (6认同)

How*_*ant 5

//do some things, but I gotta be careful I don't do anything to vec
Run Code Online (Sandbox Code Playgroud)

澄清:你需要小心,你不做任何事情vec需要一个先决条件.你可以做任何事情vec,它要求任何先决条件.例如,您可以指定vec新值.你可以打电话vec.clear().你可以打电话vec.size().但是不要调用vec.pop_back()因为该成员函数有前提条件.

  • 如果对每个人都不是很明显,我会澄清你不能做任何需要先决条件的事情_而不是先检查先决条件.可以调用`if(!vec.empty())vec.pop_back();`因为在调用`vec.empty()之后你就知道满足前提条件了 (2认同)