9

这:

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;
}
4

2 回答 2

11

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

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

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

其次,对于大多数类型,分配该类型的移动对象是完全合法的操作;这对于基本类型(如 )总是如此,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()?

此外,不要忘记 C++ 的理念是为您提供强大的功能和(最常见的)设计指南,但如果您真的想这样做,“让您大吃一惊”。

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

于 2013-02-25T20:08:33.130 回答
5
//do some things, but I gotta be careful I don't do anything to vec

澄清:您需要注意不要做任何vec需要先决条件的事情。你可以做任何不需要vec任何先决条件的事情。例如,您可以分配一个新值。你可以打电话。你可以打电话。但是不要调用,因为该成员函数有一个先决条件。vecvec.clear()vec.size()vec.pop_back()

于 2013-02-25T20:34:08.383 回答