Как объявить объект недействительным после вызова функции в C ++ 11? - PullRequest
0 голосов
/ 14 декабря 2011

В любом случае, в C ++ 11 входной аргумент функции может быть объявлен недействительным после возврата из функции?

В качестве простого примера рассмотрим, что у меня есть прямоугольный объект с координатой для нижнего левого угла и координатой для верхнего правого угла. Если я передам этот объект прямоугольника по неконстантной ссылке на функцию, функция свободна побочно воздействовать на память прямоугольника на месте, как она считает нужным. Что если эта функция должна масштабировать ее, а не копировать в новую память, а просто хочет работать на месте, как мы можем в C ++ 11 объявить, что после возврата функции содержимое переданного прямоугольника перестает быть допустимым, поскольку оно возможно, была изменена вызванной функцией?

Я бы не хотел изменять класс прямоугольника, но вместо этого в объявлении вызова функции есть какой-то способ указать, что память, переданная по ссылке, должна считаться недействительной по возвращении из функции, а компилятор должен выдавать ошибку. если вызывающий пытается использовать его после возврата вызова функции. Есть ли способ сделать это в C ++ 11?

Ответы [ 4 ]

3 голосов
/ 14 декабря 2011

Вы можете попасть туда на полпути:

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.)

1 голос
/ 14 декабря 2011

Передайте 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());

Сказав все это, это звучит как проблема дизайна. Можете ли вы реструктурировать свои функции, чтобы в этом не было необходимости?

0 голосов
/ 14 декабря 2011

Я бы хотел [хотел бы] иметь в объявлении вызова функции какой-то способ указать, что память, переданная по ссылке, должна считаться недействительной по возвращении из функции, и чтобы компилятор выдавал ошибку, если вызывающая сторонапытается использовать его после возврата вызова функции.

Я думаю, что вы путаете несколько вещей здесь.

Например, вы не передаете объект памяти функции, а объект (изтип rectangle). Объект - это больше, чем блоб памяти.
У объекта есть конструктор run, превратить каплю памяти в объект и установить объект в определенное состояние.Когда объект умирает, его деструктор будет запущен и превратит объект в блок памяти снова.Между этими двумя объектами находится объект.
Чтобы сделать объект недействительным, вам нужно либо установить один или несколько флагов, которые являются частью состояния объекта и аннулирования сигнала (это делают потоки ввода-вывода), либо вызвать его деструктор.- что (обычно) вы должны делать только косвенно, либо delete ing и объектом, созданным с использованием new, либо неявно, позволяя ему выпасть из области видимости (для автоматических объектов).

Это оставляет функции для изменения объектов, переданных им.
Функция указывает вероятность того, что онаможет изменить аргумент с помощью сигнатуры и, взглянув на , как объект передается функции , вы увидите, может ли функция его изменить.Если вам нужно вызвать функцию и вам нужно передать объект, который по какой-то причине нельзя изменить, в качестве аргумента, для которого функция указывает, что он может измениться, вам нужно передать copy этого объекта, а не реальной вещи.

Если вы хотите запретить использование объекта после того, как он был использован в качестве аргумента функции, по какой-то причине, которую я здесь не коснулся, вы можете просто поместить его в небольшую ограничивающую область:

void f()
{
  g();
  {
    rectangle rect(...);
    h(r);
  } // rect dies here
  // rect not accessible here
  g();
}
0 голосов
/ 14 декабря 2011

В нашем примере, как масштабирование прямоугольника сделает его недействительным?Если вы изменяете объект на месте, он должен оставаться действительным, иначе ваша операция бесполезна.

Как вызывающая сторона, при передаче объекта в функцию по неконстантной ссылке вы всегда должны ожидать побочные эффекты.

Единственная причина, по которой объект стал бы действительно недействительным, - это если вы от него отойдете.В этом случае вызывающая сторона должна явно передать его, используя std::move, чтобы они знали, что объект впоследствии недействителен.

...