0

在 C++11 中是否有在函数返回后将函数的输入参数声明为无效?

举个简单的例子,假设我有一个矩形对象,其左下角坐标和右上角坐标。如果我通过对函数的非常量引用传递此矩形对象,则该函数可以自由地对矩形内存产生副作用,因为它认为合适。如果该函数需要缩放它而不是复制到新内存只是想在原地工作怎么办,我们如何在 C++11 中声明函数返回后,传入的矩形的内容不再有效,因为它们可能已经被调用的函数修改了?

我不想修改矩形类,而是在函数调用的声明中采用某种方式来指示通过引用传入的内存在从函数返回时应被视为无效,并且如果调用者则让编译器给出错误尝试在函数调用返回之后使用它。有没有办法在 C++11 中做到这一点?

4

4 回答 4

3

你可以走到一半:

void function(rectangle&& x) // r-value reference
{
    // ...
}

rectangle r;

function(r); // error
function(std::move(r)); // okay, explicitly made into an rvalue

// now (by convention) r shouldn't be used, because it's been moved

也就是说,类型系统是 C++,如果您再次使用它,它的强度不足以给您一个错误。

不过,我质疑你的设计。复制有什么问题?或者为什么不在函数名中明确说明参数将被修改?(如std::swap。)

于 2011-12-14T12:41:54.183 回答
1

传递Boost.Optional作为对函数的引用,并让函数在最后重置变量。

void MyFunction(boost::optional<Rectangle> &rectangle)
{
    // Do something with rectangle here
    rectangle.reset();
}

boost::optional<Rectangle> rectangle(Rectangle(0, 0, 0, 0));
// You can also set the optional rectangle to another value
rectangle = Rectangle(100, 100, 200, 200);
MyFunction(rectangle);
// Now rectangle won't be initialised and shouldn't be used
ASSERT(!rectangle.is_initialized());

说了这么多,这听起来有点像设计问题。您可以重新构建您的功能,这样就没有必要了吗?

于 2011-12-14T13:19:01.293 回答
0

在我们的示例中,缩放矩形如何使其无效?如果您就地改变对象,它应该保持有效,否则您的操作没有用。

作为调用者,当通过非常量引用将对象传递给函数时,您应该始终期待副作用。

一个对象变得真正无效的唯一原因是如果你离开它。在这种情况下,调用者必须使用 显式传递它std::move,因此他们知道该对象之后无效。

于 2011-12-14T12:41:04.853 回答
0

我会[想要]在函数调用的声明中以某种方式指示通过引用传递的内存在从函数返回时应被视为无效,并且如果调用者尝试在之后使用它,编译器会给出错误函数调用返回。

我认为你在这里混淆了一些事情。

一方面,您不会将内存块传递给函数,而是将对象(类型为rectangle)。一个对象不仅仅是一块内存。
一个对象已经运行了它的构造函数将一块内存变成一个对象,并将对象设置为某种确定的状态。当对象死亡时,它的析构函数将运行并再次将对象变成内存块。在这两者之间,它是一个对象。
要使对象无效,您需要设置一个或多个标志,这些标志是对象状态和信号失效的一部分(IO 流会这样做),或者您需要调用它的析构函数——(通常)您应该只间接地这样做经过delete使用 ing 和对象创建new,或者通过让它超出其范围来隐式创建(对于自动对象)。

这留下了改变传递给它们的对象的函数。
函数通过其签名表明它可能更改参数的可能性,并查看对象如何传递给函数,您会看到函数是否会更改它。如果你需要调用一个函数并且你需要传递一个由于某种原因不能改变的对象作为函数指示它可能改变的参数,你需要传递该对象的副本,而不是传递真实的东西。

如果你想阻止一个对象在它被用作函数参数之后被使用,我在这里没有提到,你可以简单地将它放入一个小的封闭范围:

void f()
{
  g();
  {
    rectangle rect(...);
    h(r);
  } // rect dies here
  // rect not accessible here
  g();
}
于 2011-12-14T14:45:24.710 回答