Safe in C# not in C++, simple return of pointer / reference
Asked Answered
U

7

4

C++ code:

person* NewPerson(void)
{
  person p;
  /* ... */
  return &p; //return pointer to person.
}

C# code:

person NewPerson()
{
  return new person(); //return reference to person.
}

If I understand this right, the example in C++ is not OK, because the p will go out of scope, and the function will return a wild pointer (dangling pointer).

The example in C# is OK, because the anonymous new person will stay in scope as long as there is a reference to it. (The calling function gets one.)

Did I get this right?

Ultrasonics answered 10/12, 2011 at 11:57 Comment(2)
You're comparing apples to oranges!Waylay
Maybe, but they are both fruit. :)Ultrasonics
B
2
person* NewPerson(void)
{
  person p();
  /* ... */
  return &p; //return pointer to person.
}

p is not a person, see most vexing parse. As such, you'd get a compiler error.

For the rest, yes you're right.

Bihar answered 10/12, 2011 at 12:2 Comment(0)
T
4

The example in C++ is not ok because the 'p' will go out of scope, and the function will return an invalid pointer.

Correct.

The example in C# is ok because the anonymous 'new Person' will stay in scope as long there is any reference to it.

That is more or less correct but your terminology is not quite right. Scope in C# is the region of text in which an unqualified name can be used. The object here does not have a name. Lifetime is the period of runtime during which a storage location is guaranteed to be valid. Scope and lifetime are connected; when control leaves code associated with a scope, the lifetimes of locals declared within that scope are usually permitted to end. (There are situations where lifetimes of locals are longer or shorter than the time when control is in their scope though.)

Also, note that it is not any reference to the Person object that keeps it alive. The reference has to be rooted. You could have two Person objects that reference each other but are otherwise unreachable; the fact that each has a reference does not keep them alive; one of the references has to be rooted.

Tinstone answered 10/12, 2011 at 15:47 Comment(0)
B
2

The scoping rules in this example are analogous but in C# if the returned value is assigned to something then it will not be garbage collected as long as something holds a reference to it. If it's not assigned to something, nothing holds a reference to it and it will be garbage collected next time the collector executes

Blocker answered 10/12, 2011 at 12:1 Comment(0)
B
2
person* NewPerson(void)
{
  person p();
  /* ... */
  return &p; //return pointer to person.
}

p is not a person, see most vexing parse. As such, you'd get a compiler error.

For the rest, yes you're right.

Bihar answered 10/12, 2011 at 12:2 Comment(0)
P
1

In C++, that 'p' will live on the stack and thus get clobbered when the function returns. In C#, the garbage collector knows to not clobber it until the last reference is lost.

('clobber' being used loosely here... :p)

Photocomposition answered 10/12, 2011 at 12:1 Comment(2)
Yes i dont understand clobbered :)Ultrasonics
I should have been more technical :). I just meant that it no longer exists in a validly accessible way. Until it gets over written, the object will still exist in the place where it was, but once the variable goes out of scope (in the C++ version), there is no guarantee (and it actually becomes very, very likely) that the object will very soon be overwritten.Photocomposition
D
1

Yes, you got it right.

However, in C++ you would really do like this

person NewPerson()
{
  person p;
  /* ... */
  return p; //return person.
}

and be pretty sure that in a call

person x = NewPerson();

the compiler will optimize out the copying of the return value.

Danialdaniala answered 10/12, 2011 at 12:16 Comment(3)
OK, but it will not be ompimized in speed, right? Because a pointer is more quick to return? (or maybe thats the good option in c++ do make factoring functions)Ultrasonics
In this particular case the language specifically allows the compiler to omit the copying of the return value and construct it in place in x. Most every compiler takes advantage of this.Danialdaniala
ok, so it will have the same speed, as if you returned a pointer to a new person?Ultrasonics
R
0

Did i get this right?

Yes.

BTW: in C++ person p(); declares a function and will not call the default ctor of person. Just write person p;

Rumal answered 10/12, 2011 at 12:2 Comment(0)
E
0

This will not work in C++ because you are returning a reference to a temporary which will be destroyed once the function is over. You need to create a new person on the heap and then return a reference to that.

Empirical answered 10/12, 2011 at 12:2 Comment(2)
Beside the mistake with person p() instead of person p - p is not a temporary object (in the C++ wording).Rumal
Sorry you are correct - I feel like down-voting my own answer now :OEmpirical

© 2022 - 2024 — McMap. All rights reserved.