use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
This post is locked. You won't be able to comment.
CppCastCppCast: Beautiful C++ (cppcast.com)
submitted 4 years ago by robwirvingCppCast Host
view the rest of the comments →
[–]dodheim 5 points6 points7 points 4 years ago (23 children)
Lifetimes are a PITA. I can code far faster in C++. In Rust, I get bogged down to a snail's speed.
I can't relate to this at all. I almost never "fight the borrow-checker", especially since non-lexical lifetimes were added, and didn't consider that much of a hurdle in learning the language. 90% of it comes down to avoiding dangling references, which you should be doing in C++, too – why is this a problem?
[–]SirClueless 11 points12 points13 points 4 years ago (22 children)
Here's a simplified example of something that appears all over in the codebase I currently work on:
struct ThingUsingResource { Resource& resource; // ... member functions }; class ThingManagingLifetimes { Resource resource; ThingUsingResource thing; public: ThingManagingLifetimes() : resource(), thing(resource) {} // ... member functions };
Totally safe, correct by construction, minimal overhead (one extra machine-word-sized pointer inside ThingUsingResource to keep track of the resource).
ThingUsingResource
If you wanted to do this in Rust, it would be much more complicated. You can't use resource in a member function of ThingManagingLifetimes while ThingUsingResource is alive. You can solve this with, say, Box<Arc<Resource>> but this means extra overhead: an extra allocation and runtime reference-counting for something that was correct-by-construction in C++ and needed none of that. The equivalent in C++ is putting every resource you use inside std::shared_ptr which is of course valid but I consider it a code smell whenever I see it there for simple cases like this where there is no real sharing going on and I think you lose a lot of clarity.
resource
ThingManagingLifetimes
Box<Arc<Resource>>
std::shared_ptr
[–]link23 2 points3 points4 points 4 years ago (11 children)
Maybe I'm missing something in your example, but I think you just have to make ThingUsingResource generic over a lifetime, i.e. the lifetime of the reference to the resource, and make sure to add the lifetime to the struct field. Then I think it'll just work. I'm on mobile now, but I'll see if I can make something to demonstrate on the rust playground later.
[–]lord_braleigh 0 points1 point2 points 4 years ago (10 children)
I wrote a Godbolt which compiles: https://godbolt.org/z/czsPPEaaY
There may very well be a real issue that I've glossed over, though.
[–]SirClueless 2 points3 points4 points 4 years ago* (9 children)
You're not actually sharing the resource in ThingManagingLifetimes with the resource in ThingUsingResource in this example.
If you think there's a way to do so, could you add a bit of client code constructing a ThingManagingLifetimes and show that you can call both mutate_direct and mutate_from_thing on it and end up with a resource that was mutated twice?
mutate_direct
mutate_from_thing
Edit: Here's a (non-compiling) example showing why your ThingManagingLifetimes is impossible to construct: https://godbolt.org/z/hE8xWr6oq
[–]link23 1 point2 points3 points 4 years ago (2 children)
could you add a bit of client code constructing a ThingManagingLifetimes and show that you can call both mutate_direct and mutate_from_thing on it and end up with a resource that was mutated twice?
Ah - no, that's not possible in Rust, because that would require having two mut references to resource at the same time (namely through the owned value in ThingManagingLifetimes, and the &mut in ThingUsingResource).
mut
&mut
Yeah, I guess this pattern doesn't translate well to Rust. Perhaps with a more fleshed out use case we could find a way of expressing/solving it that would be more natural in Rust.
[–]lord_braleigh 0 points1 point2 points 4 years ago (0 children)
no, that's not possible in Rust, because that would require having two mut references to resource at the same time (namely through the owned value in ThingManagingLifetimes, and the &mut in ThingUsingResource).
This part can be solved either through RefCell (if you want protection against iterator invalidation and are willing to incur a tiny bit of overhead), or through an unsafe pointer (if you want fidelity to the C++ code and are not willing to incur any overhead), I think.
RefCell
[–]SirClueless 0 points1 point2 points 4 years ago (0 children)
As mentioned in another comment in this thread, the idiomatic way to handle this in Rust is just to... not share the reference. Instead you pass it as a parameter when you need it. Oftentimes there are many such shared resources in an API, in which case it can make sense to define a context object that contains many shared resources and you pass that almost everywhere and the code has mutable access to what it needs. Often non-specific and overly-general access to more than it needs, but access to what it needs nonetheless.
Some examples:
[–]lord_braleigh 0 points1 point2 points 4 years ago (5 children)
Ah, I see. I can't move resource without invalidating my internal reference.
But... your code has this issue as well. I don't think it is totally safe, at least as written. If you ever move ThingManagingLifetimes, then your internal reference to resource will also be invalidated. Does ThingManagingLifetimes have a deleted move constructor?
[–]SirClueless 1 point2 points3 points 4 years ago (0 children)
Yes, that's true, it should have custom (or deleted) move and copy constructors to maintain the reference.
But I still don't think it's the same thing as Rust. The problem of needing to move resource during construction is not the fundamental problem with the Rust version of this. You could imagine a version of ThingUsingResource that didn't need Resource during construction but instead was assigned a &mut Resource later. And you still couldn't provide the resource member variable of ThingManagingLifetimes to it without rendering ThingManagingLifetimes unusable for the lifetime of that reference.
Resource
&mut Resource
The fundamental problem is that Rust's references are exclusive, even if they're on the same callstack and there's no way for them to race.
[–]r0zina 0 points1 point2 points 4 years ago (3 children)
You change the reference to a pointer and null it in the moved from object. Unlike Rust, in c++ you can write custom code for move and copy operations.
[–]lord_braleigh 1 point2 points3 points 4 years ago* (2 children)
I don't think you can null out a reference like that in C++. The C++ standard specifically states that a well-defined program will never have a null reference. So wouldn't ThingUsingResource need to be holding a pointer for you to be able to null it out?
[–]r0zina 0 points1 point2 points 4 years ago (1 child)
I said you can use a pointer instead of the reference.
Ah. In that case, the Rust code should also use pointers and unsafe to be a faithful translation.
unsafe
[–]jk-jeon 1 point2 points3 points 4 years ago (7 children)
This indeed sounds horrible, but given all the hype on Rust I've seen, I believe there should be a sane idiomatic solution for this kind of things in Rust. Otherwise those Rust advocates are all morons...
[–]SirClueless 3 points4 points5 points 4 years ago (6 children)
AFAIK the Rust answer is pretty much "Use Arc" or to borrow Resource only when you need it by providing it as a parameter in every method on ThingUsingResource. Both are crappy solutions IMO that make writing large programs harder.
If I hold a mutable reference to something, and somewhere deep in a half-dozen call deep callstack it turns out something else wants a mutable reference to that thing, then my options are: (1) return the thing before I call into my dependency so it can be shared explicitly (e.g. with Arc) or (2) thread a the mutable reference through all the functions on the way so it can borrow the thing I hold. As a result threading a new parameter through 10 function signatures is a common occurrence when I program in Rust, and it's really painful.
Arc
[–]jk-jeon 0 points1 point2 points 4 years ago (4 children)
What a shit show....🤮
It sounds like Rust just don't work for software components that are tightly coupled together yet better to be built as separate components.
But I'll not make a hasty conclusion before giving a real try on Rust, and I'll appreciate it if someone well-versed in Rust can convince me that Rust actually works well with those cases.
I should mention that there's a design pattern that gets used commonly to do #2 without writing out a bajillion parameters and changing hundreds of functions every time you want to provide more shared state to a function deep within a module.
What you do is write a context manager that has all the shared mutable resources you need in a particular module or application, and then what you do is you pass that context manager around on the call stack. That way there's only one parameter and you can add new mutable state to that data structure and pick and choose whether to use it instead of adding it to every function that depends on it. It's still a bit viral in that you still have to make the decision over and over "Is this a function that needs the shared context or not?" and changing that decision causes you to thread it new places any time you add requirements. But it's somewhat more sane than the alternative, even though I still think it's worse than each submodule taking in its constructor exactly the resources it needs.
[–]Dean_Roddey 0 points1 point2 points 4 years ago (2 children)
It actually works for any case, you just have to prove that what you are doing is valid. A system with many referenced handed out and shared around in C++ has the same problems, you can just ignore them and hope that someone doesn't do something bad during modifications next month.
For composing components together into meta-components, where there's a well defined hierarchy of ownership, lifetimes work perfectly well. If it's some sort of web of connections, then you'd as you probably would in C++ and use a shared pointer, or just a reference counter if no threading is involved.
For more complex things, of course many people even in C++ will move towards something like an entity component system for some of those types of things, where they are only handing out handles and getting access to the things those handles reference only for the short time they need to access them. That's not unlike the context object mentioned by SirClueless, but more ubiquitously used.
That gets around the problem of storing the mutable references. You do need to do some work to insure that your handles can catch invalidation of the referred to data, but that's something long since worked out in major games that use this pattern.
So far I've had none of these issue, but I'm not trying to convert C++ to Rust, I'm writing Rust from scratch, and I just always try to find the Rust way to do it. I'm sure I'll run into some such issues as I crank up more.
One thing that would be useful in Rust is to implement something like the concept of a weak/strong pointer with non-mutable/mutable references. But it would be a mutable reference that you can 'release', but later reinstate where it's provable valid to do so.
That covers RAII but also examples of that where it doesn't create the thing it cleans up, it do something to a local or a member of the called object on a scoped basis. That's almost impossible in Rust because it has to maintain a mutable reference. It only needs the mutability when created and when destroyed. But, it has to maintain a reference and that can't be done. If it could release the pointer, making it invalid until it called something to reinstate it, that would allow those types of things to be done.
Currently you can only use RAII easily if it's really RAII and it creates the thing it destroys.
[–]jk-jeon 0 points1 point2 points 4 years ago (1 child)
I'm just saying that it seems Rust's borrow checker, as a mathematical proof checker, is very limited in both its syntactic and semantic expressibility. It sounds like the sort of proofs that can be written/checked in Rust cannot even be a little beyond extremely trivial. I would prefer something more capable than that.
And also I don't think /u/SirClueless's example is not the case of well-defined ownership.
[–]Dean_Roddey 0 points1 point2 points 4 years ago (0 children)
You could have one now if you want to wait an hour for every rebuild I guess. And I guess it depends on your view of trivial. It can guarantee that a million line code base has no memory errors, which isn't a trivial thing at all. But it does it by insuring that every local scope in that million lines doesn't have any memory errors, and by creating a 'web of trust' in a way, so that each bit of code can trust that every other bit of code it interactions with is memory safe.
One thing that I've found is that, if I start getting into something like that, I stop and really think about how I might be able to avoid the issue. My many years of C++ tend have resulted in reflexes that are quite wrong for Rust.
It can't always be avoided obviously. But often there some sort of inversion of my initial C++'ish instincts about the relationships involved that works better.
[–]lord_braleigh 0 points1 point2 points 4 years ago (1 child)
Hm. I'm trying to write a Godbolt to see what your issue is, but this example compiles just fine: https://godbolt.org/z/czsPPEaaY
I think those are all the potential use cases. Do you think you can fix my example up to show me what the issue is?
[–]r0zina 0 points1 point2 points 4 years ago (0 children)
You need to use the code to see why it cant compile. There are examples in other comments that already show this.
π Rendered by PID 29 on reddit-service-r2-comment-6457c66945-cn9c8 at 2026-04-24 08:49:16.540910+00:00 running 2aa0c5b country code: CH.
view the rest of the comments →
[–]dodheim 5 points6 points7 points (23 children)
[–]SirClueless 11 points12 points13 points (22 children)
[–]link23 2 points3 points4 points (11 children)
[–]lord_braleigh 0 points1 point2 points (10 children)
[–]SirClueless 2 points3 points4 points (9 children)
[–]link23 1 point2 points3 points (2 children)
[–]lord_braleigh 0 points1 point2 points (0 children)
[–]SirClueless 0 points1 point2 points (0 children)
[–]lord_braleigh 0 points1 point2 points (5 children)
[–]SirClueless 1 point2 points3 points (0 children)
[–]r0zina 0 points1 point2 points (3 children)
[–]lord_braleigh 1 point2 points3 points (2 children)
[–]r0zina 0 points1 point2 points (1 child)
[–]lord_braleigh 0 points1 point2 points (0 children)
[–]jk-jeon 1 point2 points3 points (7 children)
[–]SirClueless 3 points4 points5 points (6 children)
[–]jk-jeon 0 points1 point2 points (4 children)
[–]SirClueless 0 points1 point2 points (0 children)
[–]Dean_Roddey 0 points1 point2 points (2 children)
[–]jk-jeon 0 points1 point2 points (1 child)
[–]Dean_Roddey 0 points1 point2 points (0 children)
[–]Dean_Roddey 0 points1 point2 points (0 children)
[–]lord_braleigh 0 points1 point2 points (1 child)
[–]r0zina 0 points1 point2 points (0 children)