Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Yet another RAII discussion  (Read 14280 times)

0 Members and 1 Guest are viewing this topic.

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Yet another RAII discussion
« on: February 10, 2016, 01:21:43 pm »
To be honest if you stick to modern C++ with RAII memory leak tracking will become obsolete pretty quickly.

Alternatively, memory leak tracking solves the same problem as RAII does, but does not involve the extra overhead and ugly syntax of smart pointers. 

Except that memory leak tracking alone is sufficient to find any problems. 

RAII alone is not sufficient to prevent memory leaks (although it certainly helps), as it of course relies on there being no programming errors, in either your code or 3rd party library code.

So, if you're choosing between the two, memory leak tracking is a better choice.

Just another opinion.  :P

Satus

  • Guest
Re: Yet another RAII discussion
« Reply #1 on: February 10, 2016, 02:08:55 pm »
Quote
Alternatively, memory leak tracking solves the same problem as RAII does, but does not involve the extra overhead and ugly syntax of smart pointers. 

It does not solve problems, most of the time it creates tons of problems on it's own.
Also what overhead are you talking about?

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: Yet another RAII discussion
« Reply #2 on: February 10, 2016, 04:16:42 pm »

Satus

  • Guest
Re: Yet another RAII discussion
« Reply #3 on: February 10, 2016, 07:27:42 pm »
So unique_ptr has zero or almost zero overhead.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Yet another RAII discussion
« Reply #4 on: February 10, 2016, 07:28:37 pm »
Oh nice, another discussion about RAII. Fortunately we haven't had enough of them in the past. If there is really a need to discuss this yet another time, start another thread, and don't hijack the thread about leaks in SFML.

Alternatively, memory leak tracking solves the same problem as RAII does, but does not involve the extra overhead and ugly syntax of smart pointers.

Except that memory leak tracking alone is sufficient to find any problems.
So, when you have the choice between a technique to fix a problem after it occured, and one that prevents it from even appearing in the first place, you decide for the former. Sounds reasonable.

The arguments are always the same, and they're easily refuted. Please read this article about RAII.

http://stackoverflow.com/questions/22295665/how-much-is-the-overhead-of-smart-pointers-compared-to-normal-pointers-in-c
Maybe you should read the links you're posting. Smart pointers have no overhead, when used in a way semantically equivalent to manual memory management.

That's why one doesn't argue with shared pointers. You would have to compare it to an equivalent hand-crafted situation, i.e. shared ownership with reference counting, type-erased deleters and thread safety. Pretty sure that's not free either ;)
« Last Edit: February 10, 2016, 07:34:18 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

DarkRoku12

  • Full Member
  • ***
  • Posts: 203
  • Lua coder.
    • View Profile
    • Email
Re: Yet another RAII discussion
« Reply #5 on: February 10, 2016, 08:06:27 pm »
what overhead are you talking about?

There's about a bazillion articles on it, but here's one.

Normally you must not even notice the overhead of smart pointers.

On Channel9 from Microsoft , we can find talks about modern C++. And Bjarne Stroustrup (Creator of C++) and Stephan T. Lavavej (maintainer of Visual Studio's C++ Standard Library implementation) always recommend the use of smart pointers when possible. Without to mention that ISO C++ recommend it
I would like a spanish/latin community...
Problems building for Android? Look here

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: Yet another RAII discussion
« Reply #6 on: February 11, 2016, 01:34:55 pm »
Oh nice, another discussion about RAII. Fortunately we haven't had enough of them in the past. If there is really a need to discuss this yet another time, start another thread, and don't hijack the thread about leaks in SFML.

Incidentally, I didn't bring it up.  I only responded because, unprompted, eXpl0it3r critiqued the use of memory leak detectors by the thread author by suggesting RAII made them obsolete (which is fine, he's sharing an opinion).  So even though you quoted me, I'll assume your sarcastic reprimand was aimed at eXpl0it3r.

Although I am still a little confused.  You ask that we not hijack this thread to discuss RAII.  You follow that statement immediately with a discussion of RAII.  That in itself does not make a lot of sense. 

Normally, the point of doing such a thing would be to have a debate.  I guess I'll assume you're not interested in such a debate however, or that your rules of hijacking threads apply only to others and not yourself.

I'm ok with that, though.  Given that you filled your response with both sarcasm and insults, things a person doesn't do when seeking a positive and productive exchange of ideas, I wouldn't have been interested anyway.  I try to communicate in a positive manner and with an open mind, even and especially with people I disagree with.  If you approach things being condescending and closed minded, you neither end up learning anything new yourself, nor convincing others of your opinion.  So the "debate" is a waste of everyone's time.
« Last Edit: February 11, 2016, 01:41:55 pm by Jabberwocky »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Yet another RAII discussion
« Reply #7 on: February 11, 2016, 05:23:31 pm »
Incidentally, I didn't bring it up.  I only responded because, unprompted, eXpl0it3r critiqued the use of memory leak detectors by the thread author by suggesting RAII made them obsolete (which is fine, he's sharing an opinion).
He's actually making a good point, and there's a ton of resources to be found on the Internet that back up his claim. In this forum alone this has been discussed so often that it almost seemed like people would agree.

You ask that we not hijack this thread to discuss RAII.  You follow that statement immediately with a discussion of RAII.  That in itself does not make a lot of sense.
It was mainly a link to my article, hoping that people will read it and I don't have to re-iterate everything again. An in-depth reasoning can be found there.

Given that you filled your response with both sarcasm and insults, things a person doesn't do when seeking a positive and productive exchange of ideas, I wouldn't have been interested anyway.
Sarcasm yes, which shouldn't be surprising given that this very topic has been discussed to death already, but I don't see any insults. I'm sorry if my post came across that way. I sometimes write in a challenging way with rhetoric questions to make people reflect and question what they've heard.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: Yet another RAII discussion
« Reply #8 on: February 11, 2016, 07:56:25 pm »
He's actually making a good point, and there's a ton of resources to be found on the Internet that back up his claim. In this forum alone this has been discussed so often that it almost seemed like people would agree.

So the rule is, you can discuss RAII if you are proposing it is a useful solution.

You cannot discuss RAII if you are critiquing its use as a solution - that's hijacking.
Is this correct?

Truthfully, that strikes me as a bias to shut down arguments you disagree with.

It was mainly a link to my article, hoping that people will read it and I don't have to re-iterate everything again. An in-depth reasoning can be found there.

I have read it.  It's a good article.  But it does not mean that there is not also good in-depth reasoning NOT to use RAII.  I think you are mistaken if you believe your article is programming gospel that should override any and all discussion on it.  The internet is equally filled with people who critique RAII and smart pointers as those who advocate for it.

I don't see any insults. I'm sorry if my post came across that way.

Thanks for saying sorry, I appreciate it.
There's a few things which were pretty inflammatory.  Here's one:

Maybe you should read the links you're posting. Smart pointers have no overhead, when used in a way semantically equivalent to manual memory management.

I obviously did read the article.  I wouldn't have posted it otherwise.  That's an extremely dismissive and insulting thing to say.  I would also argue you're incorrect.

Here's a quote from the top rated answer from that article.

Quote
std::unique_ptr has memory overhead only if you provide it with some non-trivial deleter.

std::shared_ptr always has memory overhead for reference counter, though it is very small.

std::unique_ptr has time overhead only during constructor (if it has to copy the provided deleter) and during destructor (to destroy the owned object).

std::shared_ptr has time overhead in constructor (to create the reference counter), in destructor (to decrement the reference counter and possibly destroy the object) and in assignment operator (to increment the reference counter).

Granted, he does say the performance hit is small.  But it is 100% incorrect to say they have no overhead.  So not only did I read the article, but it explicitly talks about the overhead of smart pointers.  Relevant to the discussion, wouldn't you say?

Now, your argument is that
Quote
Smart pointers have no overhead, when used in a way semantically equivalent to manual memory management.

But that is not the discussion we're having.  No one has suggested we're merely replacing regular pointers with unique_ptr.  The discussion is whether to use RAII vs. not using RAII.  RAII, in cases where you need multiple pointers to the same memory, advocates the use of shared_ptr (even if it does recommend using it sparingly).  So it is not a choice merely between raw and unique_ptr.  That's a false equivalency.

There are certainly places in my (non-RAII) code where I have multiple pointers to the same memory.  This is wise not to overuse, but it has its place.  I do not use shared_ptr.  I do not use reference counting, either.  Rather, I have a well structured and known lifetime of this "multiply pointed to" memory, which can safely guarantee the duplicate pointers will be safe to access where used in the code.

This is faster, with less overhead, than the corresponding RAII solution would be.  Personally, in situations like this, I also find being closer to the metal, using raw pointers rather than the added abstraction of smart pointers, allows me an easier mental model of what is actually happening. I consider this valuable.

Here's another quote from the 2nd highest rated answer:

Quote
You can expect some overhead in debug builds, since e.g. operator-> must be executed as a function call so that you can step into it (this is in turn due to general lack of support for marking classes and functions as non-debug).

In my particular case, debug performance is very important.  This is because my primary code cycle is:  code, compile debug, run debug.  This is mainly because my projects are big enough that release linking is slow, which has a significant impact on the code-compile-run turn around cycle.  And there is the added advantage of being able to step immediately into the code without a mangled stack.

________

Now, I'm not saying RAII is terrible.  I think there are scenarios where it is a useful tool.  Perhaps one is in large code bases maintained by multiple programmers of various skill level, where the extra layer of safety is necessary, or the programmers lack the skill, experience, or even the just perfected habits to manage their memory manually.

For me, RAII is like someone suggesting I wear a helmet to bed, in case a meteor crashes through my roof and kills me.  I'm just not worried about the problems that RAII helps solve.  I am happy with my existing solutions.  They work fine.

You argue against this in your article.  You call this ignorant.  Let me ask you this - SFML does not use smart pointers.  Is this ignorant?  How often is SFML affected by it's lack of smart pointers?  How about in a way that has not been trivially easy to fix?  I certainly have never had a problem with SFML's use of raw pointers.

And finally,
So, when you have the choice between a technique to fix a problem after it occured, and one that prevents it from even appearing in the first place, you decide for the former. Sounds reasonable.

That's both sarcastic and snippy by the way.  ;)
But it doesn't attempt to address the point I made.  Which is that RAII does not guarantee you've fixed the problem.  As I said originally, yes, it helps prevent it.  But it does not guarantee there are no programmer errors, either in your code base, or in those of the libraries you employ.  The only guarantee is a memory leak detector.

If you'd like to call into question my reasonableness, please do so by addressing the reasoning I presented.

A final word - I get that you like RAII.  I get that it works for you.  That's cool.  But, as they say, programming is as much an art as a science.  To claim that people are foolish who chose to employ their art differently than you, that their reasoning is debunked, is a narrow minded view of the art of writing code. 

You may disagree with my reasoning.  And I with yours.  That's fine.  But I do not disrespect you for your decision.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Yet another RAII discussion
« Reply #9 on: February 11, 2016, 09:40:24 pm »
Ok, seems like we've definitely reached a point where we can split the topic. I originally didn't want to write all this, but you seem to be interested in the topic, and hopefully we can have a reasonable discussion.

So the rule is, you can discuss RAII if you are proposing it is a useful solution.
No. eXpl0it3r was not discussing but mentioning RAII. The discussions have occured 50 times here already, and counter-arguments have been defeated so often, that I felt there'd be no point in bringing the same ones up yet another time, while ignoring the counter-arguments to them. You may not have witnessed that, though.

I obviously did read the article.  I wouldn't have posted it otherwise.  That's an extremely dismissive and insulting thing to say.
It seemed to me that you were picking only the bits you like from that SO thread, in order to support your argument: "memory leak tracking [...] does not involve the extra overhead and ugly syntax of smart pointers" implying "smart pointers have extra overhead", which is wrong. Without further relativation this statement is misleading.

I would also argue you're incorrect.
Quote
std::unique_ptr has memory overhead only if you provide it with some non-trivial deleter.
That's exactly why I mentioned the "equivalent" part and even put it in italics. You're comparing apples with oranges. In 99% of the time one does not use custom deleters. And in the remaining 1% where one does, one would have to do the same thing with new/delete.

Granted, he does say the performance hit is small.  But it is 100% incorrect to say they have no overhead.  So not only did I read the article, but it explicitly talks about the overhead of smart pointers.
Sorry, but that's not true. You can very well achieve zero performance overhead with smart pointers, which was one of the core design principles of std::unique_ptr. And the SO thread mentions this if you look carefully: "std::unique_ptr has memory overhead only if you provide it with some non-trivial deleter." => "it has no overhead if you don't".

Rather, I have a well structured and known lifetime of this "multiply pointed to" memory, which can safely guarantee the duplicate pointers will be safe to access where used in the code.
Yes, and typically, you can design your code in a way so that one of these pointers owns the memory and the others are just referrers. If you know in advance who frees the memory, you don't need shared ownership. I'm not just saying this, I've written quite a lot of C++ code and really rarely felt the need for std::shared_ptr. Most of it is choosing a proper design, with clear ownership semantics. I agree that it may be more difficult in C++ than in other languages, but std::shared_ptr is truly overused.

Personally, in situations like this, I also find being closer to the metal, using raw pointers rather than the added abstraction of smart pointers, allows me an easier mental model of what is actually happening. I consider this valuable.
Fallacy #1: "I am using new/delete because I need more control over my code."
According to this logic, you'd program in C, if not Assembly.

In my particular case, debug performance is very important.  This is because my primary code cycle is:  code, compile debug, run debug.  This is mainly because my projects are big enough that release linking is slow, which has a significant impact on the code-compile-run turn around cycle.  And there is the added advantage of being able to step immediately into the code without a mangled stack.
I see, but I would really be surprised if this a) could not be deactivated (VAX has a step filter feature, so it's a matter of tools), and b) this would have a measurable impact, and c) this impact would outperform the time you lose if you make only one mistake related to manual memory management. You're paying a very high price for this.

Now, I'm not saying RAII is terrible.  I think there are scenarios where it is a useful tool.

For me, RAII is like someone suggesting I wear a helmet to bed, in case a meteor crashes through my roof and kills me.
Fallacy #5: "Unique pointers are overkill in this situation"

I'm just not worried about the problems that RAII helps solve.  I am happy with my existing solutions.  They work fine.
Fallacy #3: "Memory management is only unsafe when you use it incorrectly/in an unsafe way"

Let me ask you this - SFML does not use smart pointers.  Is this ignorant?
No, it's a consequence of smart pointers not being available in C++98, and difficult to hand-craft in a useful yet not dangerous way (to enable resource transfer). But I can assure you that we are going to use them once we switch to C++11, as well as that there have already been countless unnecessary bugs because resources were not deallocated correctly. Just look at Font.cpp, it's a big mess with tons of different resources that all need to be deallocated in different ways, and failure to load one must account for all the others. A C++11 handle class with move semantics would simplify this code dramatically, while making it more robust at the same time.

I certainly have never had a problem with SFML's use of raw pointers.
You have not been developing it. Because in the API, SFML doesn't use raw pointers that own memory. At least I don't recall an interface that expects you to allocate something with new, or gives you something that you must deallocate with delete.

That's both sarcastic and snippy by the way.  ;)
No, I'm dead serious. I don't understand why one would prefer spending time to fix errors to not making them in the first place.

Which is that RAII does not guarantee you've fixed the problem.
Fallacy #4: "Many people use smart pointers incorrectly"

Yes, it does (depending on what the problem is). When you prohibit access to manual resource management and enforce the use of strict ownership RAII classes, it's not possible to leak resources. How would it be? The destructor is guaranteed to be deterministically called -- abrupt program terminations aside. There may be a few situations where you need a more flexible/loose form of RAII, like shared ownership. And there are higher-level "leaks" like cyclic references or std::vector::reserve() that are out of RAII's scope. But it's an extremely powerful tool. You can still use a memory leak detector in addition to RAII if you need the extra safety; the fact that it can find mistakes with raw memory management is not an argument against techniques that prevent them by design.

Programmer errors are not a good argument because bugs in the memory leak detector can occur as well, and even more so with manual memory management. And as many threads in this forum (maybe this one too?) show, it's possible to use leak detectors incorrectly, or interpret their results in a wrong way. So it only guarantees something as long as you use it correctly, and we're back to the circular logic.

A final word - I get that you like RAII.  I get that it works for you.  That's cool.  But, as they say, programming is as much an art as a science.  To claim that people are foolish who chose to employ their art differently than you, that their reasoning is debunked, is a narrow minded view of the art of writing code.
I provided a ton of rational arguments for RAII, I even skimmed through many places in the Internet to collect different views on the topic and write a detailed article about it. It's not a matter of taste or "art" (fallacy #6), but hard facts. And I did not call you foolish.
« Last Edit: February 11, 2016, 10:12:38 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: Yet another RAII discussion
« Reply #10 on: February 12, 2016, 07:05:05 am »
It seemed to me that you were picking only the bits you like from that SO thread, in order to support your argument:

You mean like you just did when you only quoted the single line on unique_ptr?  And chose to delete the parts specifically discussing the overhead of other types of smart pointers?

implying "smart pointers have extra overhead", which is wrong. Without further relativation this statement is misleading.

It is not wrong.  Quit saying that.  Again, you are the one who is "picking only the bits you like" from the SO article.

The article lists the overhead associated with various different smart pointers.
That list does not say "smart pointers have no overhead".
That list does say "these types of smart pointers have this kind of overhead, which in some cases is zero.

It is fine for you to point out unique_ptr has no overhead. 

It is not fine for you to keep conveniently omitting the costs associated with shared_ptr.

It is not fine for you to keep calling me wrong, when the article clearly and plainly states there is overhead with certain aspects of smart pointers.

If you want to discuss the responsible and limited use of shared_ptr, due to the overhead it incurs, cool.  That is an informative conversation, based on the facts.

Unfortunately I'm going to need to ignore the next couple pieces of your post that continually reiterates the argument that smart pointers have no overhead.  Again, arguing for the restricted use of unique_ptr only is a different thing.  We can do that.  But it is different.

Yes, and typically, you can design your code in a way so that one of these pointers owns the memory and the others are just referrers. If you know in advance who frees the memory, you don't need shared ownership.

Ok, now we're reaching somewhere useful.
What do you do in this scenario?
Do you use a unique_ptr as the "memory owner" pointer, and a raw pointer in the "non-memory owning" copies?

If so, I actually think that is a reasonable solution.  But I think a lot of RAII advocates would have a problem with this.

But I'd also like to point out that manual memory management is completely sufficient in my case.  For my manager class which owns the memory, a simple delete call in the destructor completely handles the problem.

Fallacy #1: "I am using new/delete because I need more control over my code."
According to this logic, you'd program in C, if not Assembly.

If someone wrote a program in C, it worked, and it didn't leak memory, I would be 100% ok with this.  If they further claimed C provided all the tools they needed to achieve it, I would be 100% ok with this.

You keep speaking in absolutes.  I think this is where we will ultimately reach a stand still in our debate.  I believe in very few absolutes when it comes to coding.  I take into consideration the strengths of the coder, the requirements of the task, and the characteristics of any existing code base.  I am wiling to accept different tailored solutions (e.g. RAII vs. no RAII) depending on these factors.

regarding link-time:

I see, but I would really be surprised if this a) could not be deactivated (VAX has a step filter feature, so it's a matter of tools), and b) this would have a measurable impact,

I appreciate your suggestions.  But with large programs in visual studio, there's only so much you can do.  It's not just in my own code bases I've encountered slow link times, but also at every job I've ever worked at working on large software.

and c) this impact would outperform the time you lose if you make only one mistake related to manual memory management. You're paying a very high price for this.

You have no idea how much time, or how many mistakes I make using manual memory management.  You can assume, if you like.  Perhaps based on your own bad experiences.  But you should not project these issues onto me.

Fallacy #5: "Unique pointers are overkill in this situation"

Fallacy #XI:  "A single programming technique must be applied to all problems"

Fallacy #3: "Memory management is only unsafe when you use it incorrectly/in an unsafe way"

Fallacy #VII:  Manual memory management cannot be done safely.  It can, and has across many years in millions of programs.

Just look at Font.cpp, it's a big mess with tons of different resources that all need to be deallocated in different ways, and failure to load one must account for all the others. A C++11 handle class with move semantics would simplify this code dramatically, while making it more robust at the same time.

I had a look at Font.cpp.  Based on a very quick brows of the code:
There are 3 variables that use new/delete:  m_refCount, m_stream, and a m_streamRec. 

There are 5 calls to new.
There are 6 calls to delete.
That hardly strikes me as an unmanageable "big mess".

Some of these are due to a hand-rolled pointer-based reference count.  I probably would have advocated for a different solution.  I would not have objected to smart_ptr in this situation. 

There appears to be other dynamic memory allocation via calls to FT_Get_Glyph and FT_Done_Glyph.  Based on my quick examination, this does not appear to be something smart pointers would help with, as you are restricted to the syntax provided by FreeType.

If you consider this an unmanageable problem without smart pointers, I would suggest we have different abilities to deal with manual memory management.

You have not been developing it. Because in the API, SFML doesn't use raw pointers that own memory. At least I don't recall an interface that expects you to allocate something with new, or gives you something that you must deallocate with delete.

Yes, SFML is written with good memory management.
I have found the code a pleasure to work with.

Fallacy #4: "Many people use smart pointers incorrectly"

Fallacy#XXIII:  Smart pointers are always used correctly.
Fallacy#XXIV:  Smart pointers will guarantee your programs (and libraries you employ) do not leak memory.

There may be a few situations where you need a more flexible/loose form of RAII, like shared ownership. And there are higher-level "leaks" like cyclic references or std::vector::reserve() that are out of RAII's scope.

Exactly.
So we are in agreement memory leaks may occur regardless of the use of RAII.
That was the primary point of my original post.

Programmer errors are not a good argument because bugs in the memory leak detector can occur as well, and even more so with manual memory management. And as many threads in this forum (maybe this one too?) show, it's possible to use leak detectors incorrectly, or interpret their results in a wrong way. So it only guarantees something as long as you use it correctly, and we're back to the circular logic.

Yes, memory leak detectors can be used incorrectly.
Yes, RAII can be used incorrectly.
Anything you use incorrectly can cause problems.

I provided a ton of rational arguments for RAII, I even skimmed through many places in the Internet to collect different views on the topic and write a detailed article about it. It's not a matter of taste or "art" (fallacy #6), but hard facts. And I did not call you foolish.

Pardon, you say ignorant, not foolish.

As noted above, I believe we are at an impasse.  We believe fundamentally different things about the art of coding.

I did want to respond though, to clarify my opinion.  And to refute your repeated assertions that I was incorrect.  If you want to keep posting that, there is nothing more I can do than what I have written above. 

I also responded to to demonstrate how unhelpful it is to post these absolute "fallacy" rules, when I can just as easily post opposing fallacies.  Discussing in terms of these false absolutes does nothing to further the conversation.

However, I am genuinely interested in your technique in dealing with "multiply pointed to" memory in RAII, without the use of shared pointers.  Should you decide to elaborate.  I appreciate that aspect of the discussion.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11027
    • View Profile
    • development blog
    • Email
Re: Yet another RAII discussion
« Reply #11 on: February 12, 2016, 09:26:04 am »
How was that again with the sarcastic tone you didn't like? ::)

Anyways there's quite a bit of nitpicking going on while if one looks at the discussed points more broadly it would be clear what was meant even if it wasn't pedantically written that way.

Do smart pointers have an overhead? Yes, some of them do, mainly that ones that one should only use in rare situations and when used in such situations similar overhead would have to be introduced when manually managing memory (shared ownership/ref counting).

Does manual memory management introduce a higher probability of making a mistake (e.g. creating a memory leak)? Yes, due to the various ways a scope can be prematurely exited, the deletion of allocated memory requires more care and thus a higher probability in forgetting one or the other scenario.

Is it impossible to write non leaking applications with manual memory management? No.

Is it impossible to write bug free applications? Yes.

Should manual memory management be suggested as best practice to a new beginner or even "advanced" C++ programmer? No, because the gained performance (if any!) through MMM will not outweigh the high probability of making mistakes, in almost any application said programmer will write.

Are leak detection software useless? No, but through the guarantees that RAII makes, the chance of "random" memory leaks goes towards zero.

And finally a small analogy:
Just because a Formula 1 driver is able to drive at 200-300 km/h on normal roads, doesn't mean one should remove all the tempo limits and let everyone drive at whatever speed they want.

Since you claimed that there are many people advocating against RAII, I'd be interested in reading some sources (as long as they aren't just C advocates, we're talking here C++ after all).
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Yet another RAII discussion
« Reply #12 on: February 12, 2016, 09:51:31 am »
I'll only address the parts that are objectively about RAII. I don't think the meta-discussion about who said what and who is right on what topic leads anywhere.

Quote
Do you use a unique_ptr as the "memory owner" pointer, and a raw pointer in the "non-memory owning" copies?

If so, I actually think that is a reasonable solution.  But I think a lot of RAII advocates would have a problem with this.
Yes exactly. I don't see a problem with raw pointers, only with those that own memory.

And this is not directly related to RAII (or even pointers). It happens with all kinds of indirections in C++: pointers, references, iterators, handles... Those may become invalid. But my personal experience is that programs are generally much easier to understand and to reason about, when ownership semantics are made clear (i.e. this class holds this resource, and these classes may access it at these times). Shared pointers as a poor man's garbage collector are hardly ever a good idea (and unfortunately, many people treat them as such).


Quote
I had a look at Font.cpp.  Based on a very quick brows of the code:
There are 3 variables that use new/delete:  m_refCount, m_stream, and a m_streamRec. 

There are 5 calls to new.
There are 6 calls to delete.
That hardly strikes me as an unmanageable "big mess".
This is only memory used with C++ allocation operators. There are many other resources (e.g. FT_Library, FT_Face, FT_Stroker) which are manually managed, too.

You are right that smart pointers would not directly help (although something could be bent with custom deleters). But a customized RAII handle class could. I have a class template in mind that knows the resource type, and functions to allocate/deallocate instances. It would make sure that the deallocate function would be invoked in its destructor. Furthermore, move constructors would allow for resource transfer (e.g. between Font instances, or from local to member scope).

The idea is that this pattern:
a = load();
if (!a)
    return false;

b = load(a);
if (!b)
{
    unload(a);
    return false;
}

c = load(a, b);
if (!c)
{
    unload(a);
    unload(b);
    return false;
}

m_a = a; // transfer to member variables
m_b = b;
m_c = c;
 
could be simplified with RAII:
a = load();
if (!a)
    return false;

b = load(a);
if (!b)
    return false;

c = load(a, b);
if (!c)
    return false;

m_a = std::move(a);
m_b = std::move(b);
m_c = std::move(c);

Or even better, with exceptions. This would allow to decouple error handling, and make sure any so-far allocated resources are deallocated correctly.
a = load();     // may throw
b = load(a);    // may throw
c = load(a, b); // may throw

m_a = std::move(a);
m_b = std::move(b);
m_c = std::move(c);


Quote
Fallacy #VII:  Manual memory management cannot be done safely.  It can, and has across many years in millions of programs.
That's a strawman, the fallacy "Memory management is only unsafe when you use it incorrectly/in an unsafe way" doesn't imply yours. It's not a matter of whether it's possible to do MMM (manual memory management) correctly, but of how easy it is to do. Things that make my life easier as a programmer are good. And I claim applying RAII correctly is much easier than applying MMM correctly.


Quote
Fallacy#XXIII:  Smart pointers are always used correctly.
Fallacy#XXIV:  Smart pointers will guarantee your programs (and libraries you employ) do not leak memory.
Again, strawman. I'm not claiming either of those.

Your argument is: because mistakes are possible with both MMM and RAII, it doesnt matter what to choose.
My argument is: RAII helps considerably reduce, if not prevent, those mistakes. It should thus be chosen over MMM where possible.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: Yet another RAII discussion
« Reply #13 on: February 12, 2016, 10:35:39 am »
How was that again with the sarcastic tone you didn't like? ::)

Actually, I don't believe there was a single instance of sarcasm anywhere in my post. 

If perhaps you are noting an element of frustration, I would agree.  I did resort to a "fight fire with fire" on the "Fallacy" thing, but that was to illustrate a point.

Anyways there's quite a bit of nitpicking going on while if one looks at the discussed points more broadly it would be clear what was meant even if it wasn't pedantically written that way.

I agree with this also.

Really, Nexus and I got caught up in who is right and who is wrong, when really we likely would have both quickly agreed on the following:

Some smart pointers have overhead.  Others do not.

The overhead is small for shared_ptr, but it exists.

The overhead of using smart pointers can be minimized, or eliminated by reducing or avoiding the use of shared_ptr.

We may have debated the merits of shared_ptr and it's use in RAII, but unfortunately we didn't get that far.

I would say to Nexus, your way of approaching things right from the start put us at odds.  I am partially to blame for getting dragged in, even though I tried not to.  Still, I would suggest you may reconsider the way you approach a debate here on the forums.  You're obviously a very smart guy.  I very much appreciate the work you and the SFML team do.  I think it is brilliant software.  But nobody likes being berated. 

Perhaps you don't think you did that.  This is very much how it came across to me.  You can decide whether you want to believe that to be valid or not.  I'm just letting you know.

As fans of programming, graphics, games, and open source software, all of us here have so much in common.  It's a shame we cant treat one another with more respect.  Yet somehow, small differences in the way we approach our craft leads to this kind of showdown.  I wish we could respect those differences, even if we do debate them.  I have tried to reinforce this message throughout my posts.  But readily admit I got pissed off eventually.

Does manual memory management introduce a higher probability of making a mistake (e.g. creating a memory leak)? Yes, due to the various ways a scope can be prematurely exited, the deletion of allocated memory requires more care and thus a higher probability in forgetting one or the other scenario.

Interestingly enough, I almost never have to "new" anything outside of a constructor.  In these cases, there are no concerns with scope. 

I do use tons of stl containers.  I normally prefer containers of data over containers of pointers to data, as interation time and cache use is far better.  So there is no concern here either for new and delete, and scope issues.

Should manual memory management be suggested as best practice to a new beginner or even "advanced" C++ programmer? No, because the gained performance (if any!) through MMM will not outweigh the high probability of making mistakes, in almost any application said programmer will write.

Well, I think many would use the same logic to recommend C# over C++.  Yes, I know garbage collection is far more sinister than anything I dislike about smart pointers.  But if the argument is to be absolved of memory management, C# is superior.  Many people choose C++ over C# precisely because they wish to manually control their memory. 

I understand you disagree with this.  I am just stating what I believe.

Since you claimed that there are many people advocating against RAII, I'd be interested in reading some sources (as long as they aren't just C advocates, we're talking here C++ after all).

Sure.
Here's one.
http://seanmiddleditch.com/dangers-of-stdshared_ptr/

Now, that article is primarily against shared_ptr, although RAII is mentioned.

Quote
RAII is not a panacea. shared_ptr is an application of RAII for example. It's simply important to note that RAII - if used correctly - allows problems to be solved that automatic GC does not.

I think that article is a balanced and insightful debate of the sort we were having trouble achieving here.

Nexus, while I was writing this up, you posted your response.  I agree with you on the meta-discussion.  I suggest we drop the fight over whose fallacies are, uh, more fallacioius.  ;) 

Regarding the example you posted - yes, I would agree this is a tricky (albeit manageable) example of memory management. 

Honestly, in the case of your example, if a person said they wanted to use a smart pointer to avoid the problems of scope and early returns, I would be fine with that.

I do not think that argument extends to insisting smart pointers be used in every single scenario where memory is allocated, a core principle of RAII.  If the allocated memory can be completely handled by the tried and true method of a proper constructor, destructor, and copy/move/assignment/etc operators as necessary, I do not see this as a danger except in the hands of an inept programmer.

This above pattern is by far the most common use of managed memory I encounter in my code.

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: Yet another RAII discussion
« Reply #14 on: February 12, 2016, 10:58:33 am »
I just had a look at my use of new/delete.  I should add that I often use "new" in ResourceManager type classes, and this occurs outside of the constructor. 

I have never once had a problem with memory leaking with these classes. 


 

anything