class X {
public:
Y* getY(void) {
return &y;
}
private:
Y y;
};
}
`getY` returns a pointer to the struct field, this field is allocated as a part of the struct. There is no way (in C++) to verify that this pointer does not outlive the struct itself. In other words, your pointer may become stale, and the compiler has no way to check for it.Rust has a resource ownership model (borrow checker) that allows it to check at compile time that references do not outlive the data.
(1): See constructor number 7 here, which was designed for this purpose: http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_pt...
Nevertheless, a better solution was pointed out in an answer on the blog and by humanrebar.
[1]: https://play.rust-lang.org/?gist=78e7af18c6fc7d37d9df96be63a...
[2]: https://play.rust-lang.org/?gist=2072a18b674685f20c9d1504a88...
Then the C++ translation above should probably be a const& in C++, which is acceptable. The returned reference could in that case be stored, but it's risky and a bad practice.
class Foo {
int bar;
int& getBar() { return bar; }
}
if you take ref of bar and Foo goes out of scope well fuck. It gets even worse, eg. : vector<int> foo;
int& bar = foo[i];
foo.push_back(1)
that last line can cause foo to reallocate the buffer and bar is then invalid, meanwhile that code will compile without warnings (well I'm guessing it will I haven't done C++ in a year :) )You can see the program crash
Here is a better example : http://rextester.com/MAJDQ8375
On VC++ it will return : Reference is 0 but value is 9
On clang it will return : Reference is 32579632 but value is 9
So let's say I wasn't mutating the 0 index, VC example would work fine at runtime and then clang would suddenly start giving garbage results. This has caused me week of debugging in a big code base.
Pun intended?
Are you are familiar with the substring problem in Java? Before 1.7.0_06, substrings where created using an offset into the buffer of the original string. Nice O(1) substring creation, the textbook example for benefits of immutability. Unfortunately, if you have long-lived, but short substrings taken out of short-lived, but long parent strings, the garbage collector won't find much to collect, since the substrings keep references to their parent buffers. This was no showstopper, but without immutability or in an environment with unmanaged memory it might very well be.
This Rust snippet is about similar cases of subcomponent sharing, just on a shorter timescale: the subcomponent is exposed in a way that allows the compiler to enforce that nobody keeps a reference for longer than it is guaranteed to be valid. You may look, you may even touch, but if you want to look again you have to ask again.
Other languages get by without this by garbage collection, by excessive precautionary copying or by simply hoping that the caller won't do anything stupid. Rust is unique in achieving the same runtime behavior as the latter but without the uncertainty. As a bonus, those un-keepable references cannot escape across concurrency borders so that in-place mutability becomes a lot more manageable.
As I understand it, if you have a structure that has a pointer to something (like a User struct pointing to an array of permissions or some such), and the memory pointed to will be freed when the structure is freed.
There is a case where code can keep a reference to this pointer around longer than the user struct it belongs to, so when code tries to use it it references an invalid pointer. This is bad. Rust takes care of this in some clever ways, so you cant have a pointer/reference that outlives it's parent.
Any garbage collector could (with some overhead) prevent invalid memory access when we're talking about an object with a pointer to another object. Rust is able to validate the correctness of pointers to offsets within the stack representation of an object.
(Rust also validates the correctness of references to heap allocated objects as well, of course!)