[C++] Ownership protection

Started by
7 comments, last by Rebooted 16 years, 3 months ago
Consider the following code, in C++:
void foo(std::auto_ptr<int>);

void bar() 
{
  std::auto_ptr<int> p(new int());
  foo(p);
  foo(p);
}
There is no way of making the second call to foo(p) generate a compiler error (though it's certainly possible to generate a runtime error through a slight modification of the auto_ptr constructor). Assuming that we can implement a new version of auto_ptr with different semantics but the same philosophy of "I own this pointer", how much would one have to change the above piece of source so that the second call generates an error but the first doesn't?
Advertisement
It won't generate a compile error, but foo can certainly assert the pointer to be valid, which would raise an error on the second call.

Personally, I never use auto_ptr. Mutating copy constructors are bad mojo. boost::scoped_ptr removes this weirdness. s/std::auto_ptr/boost::shared_ptr/g would cause both function calls to result in a compile error (no copy constructor), leading the programmer to change the argument to a boost::shared_ptr<int> const&, which works just dandy.
On the face of it, it doesn't seem possible without some truly evil macro hackery. To generate a compiler error, you'd basically need the call to foo() to actually change the type of p; which isn't allowed in C++'s static type system.
Quote:Original post by Sneftel
It won't generate a compile error, but foo can certainly assert the pointer to be valid, which would raise an error on the second call.


Indeed. The issue mostly appears when one wishes to implement an auto_ptr-like object which cannot be null. Thus leading to the existence of a 'given away' state where the object cannot undergo any transformation except for being destructed. The point of this question would be to detect at compile time usage of 'given away' pointers.

Quote:s/std::auto_ptr/boost::shared_ptr/g would cause both function calls to result in a compile error (no copy constructor), leading the programmer to change the argument to a boost::shared_ptr<int> const&, which works just dandy.


I agree. However, please assume (as the original example does) that foo requires exclusive ownership.
Not possible. Type analysis is static. One line within a variable context is treated like any other.

void foo(std::auto_ptr<int>);void bar() {  std::auto_ptr<int> p(new int());  if(someProgram.halts())  {    foo(p);  }  foo(p);}
Quote:Original post by Sneftel
if(someProgram.halts())


You know you're a computer scientist, when...

Thank you for your arguments, both of you. That's pretty convincing.
You'd need linear types, which C++ definitely doesn't have.

Vault is a C-like research language with a linear type system that can do this sort of thing (ensure you never write to a closed file, etc).
I was testing something like this for serialization:
template < int Size >struct CheckSize{	enum { SIZE = (Size >= 0 ? Size : -1) };};template < int BufSize >struct Serializer{		template < class T >	Serializer< CheckSize< BufSize - sizeof(T) >::SIZE > write( T )	{		return Serializer< CheckSize< BufSize - sizeof(T) >::SIZE >();	}};template <>struct Serializer<-1>{private:	Serializer() {};};int main(){ // fails while writing 200	Serializer<10>().write( 17 ).write( 20 ).write(200);}


I believe that chaining calls would be the only way to do this, you'd probably need to wrap call to foo in a function pointer, then call it in a chain.

Quote:Assuming that we can implement a new version of auto_ptr with different semantics but the same philosophy of "I own this pointer", how much would one have to change the above piece of source so that the second call generates an error but the first doesn't?


I believe this could work:
safe_ptr<int>(new int()).call(foo)// .call(???) no longer exists in second specialization
Antheus: I still don't think that will work.

For example:
// this would give a type error:// safe_ptr<int>(new int()).call(foo).call(foo)// but this is type correct:safe_ptr<int> p(new int());p.call(foo);p.call(foo);


I think there is a way though, but I'll have to think about it. You need to make it impossible to access the raw safe_ptr, and dress it in a higher-level wrapper based on Antheus's .call idea (the resulting interface might be quite awkward to use in practice).

This topic is closed to new replies.

Advertisement