Date: Thu, 22 Apr 2021 22:02:06 +0200
Hi,
I would like to improve memory safety in C++, but before writing a real
proposal (and implementing a prototype) I would like to get some
feedback whether you think this is a useful direction.
Basically I would like to integrate a kind of borrow checker into C++
for data types that opt-in to that mechanism. For these types the
compiler enforces the invariant that you can have either one mutable
reference or arbitrary many immutable references to an object.
A straw man example could look like this:
class MyIntVector [[borrowchecker]] {
...
void push_back(int element);
[[borrows]] const_iterator begin() const;
};
void foo(MyIntVector&);
void bar() {
MyIntVector v;
v.push_back(1);
v.push_back(2);
for (int i:v) {
cerr << i;
v.push_back(3); // error: the const_iterator borrowed the object
for (int j:v) {
// this is ok, we can have arbitrary many readers
}
}
v.push_back(2); // ok now, the lifetime of the iterators has ended
foo(v); // error, implicit additional reference
foo(borrow(v)); // ok, we explicit borrow an exclusive reference
}
This is not fleshed out, of course, there are many issues and corner
cases to consider, in particular in interaction with existing code. My
question is: Would you consider this a useful direction to explore? And
if yes, would someone be interested in discussing potential design
choices (e.g., whether or not the [[borrows]] annotation of begin is
required, etc.)? These all have trade-offs and I would be happy to get
some feedback.
Best
Thomas
I would like to improve memory safety in C++, but before writing a real
proposal (and implementing a prototype) I would like to get some
feedback whether you think this is a useful direction.
Basically I would like to integrate a kind of borrow checker into C++
for data types that opt-in to that mechanism. For these types the
compiler enforces the invariant that you can have either one mutable
reference or arbitrary many immutable references to an object.
A straw man example could look like this:
class MyIntVector [[borrowchecker]] {
...
void push_back(int element);
[[borrows]] const_iterator begin() const;
};
void foo(MyIntVector&);
void bar() {
MyIntVector v;
v.push_back(1);
v.push_back(2);
for (int i:v) {
cerr << i;
v.push_back(3); // error: the const_iterator borrowed the object
for (int j:v) {
// this is ok, we can have arbitrary many readers
}
}
v.push_back(2); // ok now, the lifetime of the iterators has ended
foo(v); // error, implicit additional reference
foo(borrow(v)); // ok, we explicit borrow an exclusive reference
}
This is not fleshed out, of course, there are many issues and corner
cases to consider, in particular in interaction with existing code. My
question is: Would you consider this a useful direction to explore? And
if yes, would someone be interested in discussing potential design
choices (e.g., whether or not the [[borrows]] annotation of begin is
required, etc.)? These all have trade-offs and I would be happy to get
some feedback.
Best
Thomas
Received on 2021-04-22 15:02:09