| > That's not right. You can have a data race to a plain old integer. Sure, if your language allows unprotected access to any object from any thread. Which, I guess traditional C++ essentially does, but presumably a "Safe" C++ would eventually have an "asynchronous sharing" checker that would require any shared objects to be appropriately "protected". > > only its structure > I am not 100% sure what distinction you're making here, sorry. What's "the container" vs "its structure"? For example: std::vector<int> vec1 {1, 2};
{
const auto& cref1 = vec1.at(0);
auto& ref2 = vec1.at(1);
ref2 = 3;
auto& ref1 = vec1.at(0);
std::cout << cref1;
ref1 = 4;
// co-existing const and non-const references are permitted and memory safe here
std::cout << vec1.size();
vec1.at(0) = 5;
vec1.clear(); // <---- Rejected by the lifetime checker
// because the clear() call mutates the structure.
// Mutating the data contained in the vector is permitted though.
std::cout << cref1;
}
> Yes, in general, Rust takes a soundness-based approach. If you can't prove that it's safe, then it's not safe.The approach is not that different. The lifetime checker applies (or will apply) basically the same sorts of restrictions that the Rust compiler does (and "break" backward compatibility in the process), but only when necessary to enforce memory safety. I mean, the way the lifetime checker works is that it basically keeps track, at compile-time, of the latest possible death-time of every reference and the earliest possible death-time of the target object (or potential target objects) that each reference points at, and complains anytime the former is later than the latter. |