Question

Is there anyway in C++11 to have an input argument to a function be declared as invalid after the function returns?

For a simple example, consider that I have a rectangle object with a coordinate for the lower left corner and a coordinate for the upper right corner. If I pass this rectangle object by non-const reference to the function, the function is free to side-effect the rectangle memory in place as it sees fit. What if that function needs to scale it and rather than copying to new memory just wants to work in place, how could we in C++11 declare that after the function returns, the contents of the rectangle passed in are no longer valid as they may have been modified by the function called?

I would not want to modify the rectangle class, but instead have some way in the declaration of the function call to indicate that the memory passed in by reference should be considered invalid upon return from the function and have the compiler give an error if the caller tries to use it subsequent to the function call returning. Is there some way to do this in C++11?

Was it helpful?

Solution

You can get half-way there:

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

That said, the type-system is C++ is not strong enough to give you an error if you use it again.

I question your design, though. What's wrong with making a copy? Or why not make it clear in the function name that the argument is going to modified? (Like std::swap.)

OTHER TIPS

Pass a Boost.Optional as a reference to your function and have the function reset the variable at the end.

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());

Having said all that, this sounds a bit like a design issue. Can you re-architecture your functions so this isn't necessary?

In our example, how would scaling the rectangle make it invalid? If you mutate the object in-place, it should remain valid, otherwise you operation is not useful.

As a caller, when passing an object to a function by non-const reference you should always expect side-effects.

The only reason where an object would become truly invalid is if you move from it. In that case the caller has to explicitly pass it using std::move, so they know that the object is not valid afterwards.

I would [want to] have some way in the declaration of the function call to indicate that the memory passed in by reference should be considered invalid upon return from the function and have the compiler give an error if the caller tries to use it subsequent to the function call returning.

I think you are confusing a few things here.

For one, you do not pass a blob of memory to a function, but an object (of the type rectangle). An object is more than a blob of memory.
An object has had its constructor run, turn a blob of memory into an object, and setup the object to some definitive state. When the object dies, its destructor will run and turn the object into a blob of memory again. In between those two, it's an object.
To render an object invalid you need to either set one or more flags that are part of the object's state and signal invalidation (IO streams do that), or you need to call its destructor — which (usually) you should only do indirectly, either by deleteing and object created using new, or implicitly by letting it fall out of its scope (for automatic objects).

That leaves functions to change objects passed to them.
A function indicates the possibility that it might change an argument by its signature, and looking at how an object is passed to a function you see whether the function might change it. If you need to call a function and you need to pass an object that must, for some reason, not be changed as an argument for which the function indicates that it might change, you need to pass a copy of that object, rather than the real thing.

If you want to prevent an object from being used after it was used as a function argument for some reason I haven't touched here, you can simply put it into an small enclosing scope:

void f()
{
  g();
  {
    rectangle rect(...);
    h(r);
  } // rect dies here
  // rect not accessible here
  g();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top