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

Author Topic: What about memory leaks?  (Read 22289 times)

0 Members and 1 Guest are viewing this topic.

Rosme

  • Full Member
  • ***
  • Posts: 169
  • Proud member of the shoe club
    • View Profile
    • Code-Concept
Re: What about memory leaks?
« Reply #15 on: June 05, 2015, 08:25:05 pm »
std::unique_ptr add exactly zero overhead. None. You still have to be careful with it you know. In addition, std::unique_ptr makes your code more robust, because it forces you to understand semantics and how your possibly doing useless copies, where you should use move semantics, etc.

They way std::unique_ptr is being use is pretty much the same, so the excuses of forcing you to be more careful remains. It's just make it easier to be more careful. There are also outside situations that even if you are being extremely careful, can make your software crash. Here's a small example:

Since C++ is an exception language, you have a potential memory leak with this code:

int* p1 = new int(5);
int* p2 = new int(8);

delete p2;
delete p1;

Why? Because if the allocation to p2 fails and throws, p1 will never be destroyed. What you need to do, is surround it with catch:

int* p1 = new int(5);
int* p2 = new int(8);

delete p2;
delete p1;

int* p1 = new int();
int* p2 = nullptr;

try {
        p2 = new int();
} catch(std::bad_alloc& e) {
        delete p1;
}

delete p2;
delete p1;

Now this is one very basic example. In a real situation, it makes it so much more complex and complicated. Also the code becomes a giant mess of catch. Now look at how the code is with std::unique_ptr:

std::unique_ptr<int> p1 = std::make_unique<int>(5);
std::unique_ptr<int> p2 = std::make_unique<int>(8);

Well, yeah, that's all there is to be. My choice is made. It's simplifies. It doesn't mean you have done less. In fact, the reason why older software(pre-11) didn't have those problems, is because in a lot of cases, people developped their own smart pointers. Then came boost, and C++11. But all in all, smart pointers have been around for a long time, just that everyone had their own.

Using raw pointers to understand the concept and the danger of it is fine by me. In real situations, smart pointers is the way to go.
GitHub
Code Concept
Twitter
Rosme on IRC/Discord

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: What about memory leaks?
« Reply #16 on: June 05, 2015, 08:41:03 pm »
std::unique_ptr<int> p1 = std::make_unique<int>(5);
std::unique_ptr<int> p2 = std::make_unique<int>(8);
And to save some typing:
auto p1 = std::make_unique<int>(5);
auto p2 = std::make_unique<int>(8);
:)

Rosme

  • Full Member
  • ***
  • Posts: 169
  • Proud member of the shoe club
    • View Profile
    • Code-Concept
Re: What about memory leaks?
« Reply #17 on: June 05, 2015, 08:46:56 pm »
Oh yes for sure :) I just didn't put auto for clarification
GitHub
Code Concept
Twitter
Rosme on IRC/Discord

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: What about memory leaks?
« Reply #18 on: June 05, 2015, 08:56:23 pm »
std::unique_ptr add exactly zero overhead. None.

True, but std::unique_ptr only covers one use-case of pointers.  std::shared_ptr does have non-trivial overhead.  If you fully embrace smart pointers, solely using std::unique_ptr ain't gonna cut it.

Here's a small example:

Since C++ is an exception language, you have a potential memory leak with this code:

int* p1 = new int(5);
int* p2 = new int(8);

delete p2;
delete p1;

I understand this is only meant to illustrate a point.  But it's a horribly contrived example.  What the hell are you doing newing ints here?  Any sane programmer who only wanted his objects to live for the length of a particular scope would not use the heap.  You'll have to do better than that to convince me.

Also, for what it's worth, I don't use any exceptions in my own code.  I dislike the non-linear nature of exception handling.  I return error codes from functions that require error handling.  The only place I write try/catch blocks is when an external lib forces them on me.

Whether to use exceptions is a whole different argument.  Of course it very much depends on how resilient you need to be for unexpected scenarios, like running out of memory, or bad file access.  For things like a video game, there's no reasonable way to handle scenarios like this.  If something fundamental is malfunctioning like memory allocation, there's no point continuing on.  Having a bottom level try-catch block to log the error then abort is fine. 

Sprinkling exceptions throughout your code which cause you to jump to a whole different frame in the call stack (the exception handler) will in most cases make your game either buggy or unplayable.  So I find spending excessive amounts of time writing exception handling routines to be a waste of time.  Better to focus on ensuring you can find out about the error and correct the code, and/or advise the user as to why the game is unplayable on her system.  You're not doing anybody any favors allowing your program to limp onwards in a malfunctioning state.  And doing so may have even worse consequences, like corrupting save files.

« Last Edit: June 05, 2015, 08:59:01 pm by Jabberwocky »

Rosme

  • Full Member
  • ***
  • Posts: 169
  • Proud member of the shoe club
    • View Profile
    • Code-Concept
Re: What about memory leaks?
« Reply #19 on: June 05, 2015, 09:12:23 pm »
You missed the point of my post I believe. It's a proof of concept. Replace the int by any object if you want, put them in any situation, it doesn't matter. It shows the situation. And it's not a question of being for or against exceptions. A failed allocation is going to throw. The program don't care if you use error code, it's still going to throw if it fails. And you are supposed to be handling that case.

I know std::shared_ptr add overhead. I made a case of std::unique_ptr. But the trouble it removes from managing correctly my pointers is far better than the overhead it adds. In the end it's all about writing robust and flexible code that is easy to maintain. Personnaly, I'd rather spend more time on my algorithm, the game play, the real issues, than with some pointer problem that can be avoided by simply using smart pointers.
GitHub
Code Concept
Twitter
Rosme on IRC/Discord

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: What about memory leaks?
« Reply #20 on: June 05, 2015, 09:23:56 pm »
A failed allocation is going to throw. The program don't care if you use error code, it's still going to throw if it fails. And you are supposed to be handling that case.

I do:

Quote from: Jabberwocky
If something fundamental is malfunctioning like memory allocation, there's no point continuing on.  Having a bottom level try-catch block to log the error then abort is fine. 

(See my previous post for the full context of that quote.)

I know std::shared_ptr add overhead. I made a case of std::unique_ptr. But the trouble it removes from managing correctly my pointers is far better than the overhead it adds.
I get that.  If these are the tools you use to write your best code, great!  The way my brain works, I believe I write better code by manually handling my allocations and deletions. 

If C++12 came out and said, "we have a 100% perfect, 100% efficient garbage collector", I wouldn't use it.  Handling memory manually and explicitly is one of my primary reasons for sticking with C++ over C#, or other garbage collection languages.

Personnaly, I'd rather spend more time on my algorithm, the game play, the real issues
That exact same argument is used by people who advocate game engines like Unity over SFML.  I'm not saying it's wrong.  But I disagree it is universally the correct decision, either.
« Last Edit: June 05, 2015, 09:34:56 pm by Jabberwocky »

SpeCter

  • Full Member
  • ***
  • Posts: 151
    • View Profile
Re: What about memory leaks?
« Reply #21 on: June 05, 2015, 09:40:54 pm »

I know std::shared_ptr add overhead. I made a case of std::unique_ptr. But the trouble it removes from managing correctly my pointers is far better than the overhead it adds.
I get that.  If these are the tools you use to write your best code, great!  The way my brain works, I believe I write better code by manually handling my allocations and deletions. 
That exact same argument is used by people who think they don't make mistakes. This is like saying you don't need a safety belt because you can drive better without it.
What exactly do you think "better" code is?
Using unique_ptr for single ownership makes your code more clear and you really have to think about what you do, not playing make believe.
Shared_ptr may have a big overhead in comparison but in reality you most often don't even need shared ownership.
« Last Edit: June 05, 2015, 10:24:21 pm by SpeCter »

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: What about memory leaks?
« Reply #22 on: June 05, 2015, 09:47:25 pm »
(previous post deleted, thanks SpeCter!)

That exact same argument is used by people who think they don't make mistakes. This is like saying you don't need a safety belt because you can drive better without it.

Good point. 
But I think there's cases where using a "safety net" is good (e.g. seatbelt).  And cases where it's optional (e.g. memory garbage collection).  After all, if absolute safety was the sole and primary concern, shouldn't we all be using garbage collection?  It's still possible to write bad code with std::unique_ptr (e.g. by improperly storing the raw pointer returned from std::unique_ptr::get). 

There's always ways to hang yourself.  All I'm arguing is the choice of rope should be an individual decision by the programmer.  I almost always disagree with anyone who argues for a universal "right way" of doing things.

What exactly do you think "better" code is?

I actually find this a very interesting question. 

There's a lot of ways you could answer this.  But part of the answer, to me, is the clean expression in code of an elegant mental design.  A huge part of coding isn't the actual typing (of course!), but rather the process the coder must use to translate the mental design into code.

Everyone is going to do this a little differently.  We're all different people.  Coding is as much an art as it is a trade.  For me personally, a key part of that translation to code is to explicitly think about (and write!) the allocation and deallocation of memory. 

Using unique_ptr for single ownership makes your code more clear and you really have to think about what you do, not playing make believe.
Shared_ptr may have a big overhead in comparison but in reality you most often don't even need shared ownership.

In a sense we're agreeing here, on the importance of thinking about ownership.  Just disagreeing on the best way to do it.  Maybe you're right and unique_ptr is simply superior.  Or maybe I'm right, and the answer is relative to the coder - that they should use whatever method most works with their unique thought process behind coding.
« Last Edit: June 05, 2015, 10:44:14 pm by Jabberwocky »

SpeCter

  • Full Member
  • ***
  • Posts: 151
    • View Profile
Re: What about memory leaks?
« Reply #23 on: June 05, 2015, 10:35:54 pm »
Sorry to say that,but not using something which is meant to help you write better and safer code and saying you are better than that is bound to give you rolleyes.
Using unique_ptr doesn't take away the ability to manually and explicitly delete your unneeded memory. Not having to write delete/new is taken away from you, but you still can control when and where your memory is deleted using RAII. The only difference is that you can't fail to tidy up.

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: What about memory leaks?
« Reply #24 on: June 05, 2015, 11:07:26 pm »
not using something which is meant to help you write better and safer code and saying you are better than that

re:  the bolded
Where did I say that?

SpeCter

  • Full Member
  • ***
  • Posts: 151
    • View Profile
Re: What about memory leaks?
« Reply #25 on: June 06, 2015, 12:33:16 am »
not using something which is meant to help you write better and safer code and saying you are better than that

re:  the bolded
Where did I say that?

I believe I write better code by manually handling my allocations and deletions.


I think that pretty much fits what I said ;)

If we were talking about garbage collected memory vs. manually handled memory I would probably be on your side, but smart pointers are not garbage collection(shared_ptr is kinda in that direction but I'm mainly talking about unique_ptr).
Using unique_ptr vs. raw pointer is more like helping yourself write safer code with benefits and no downsides.(Like I said you don't lose your manual memory management, it is still you who decides when and where memory gets deleted just not explicitly by saying delete)
« Last Edit: June 06, 2015, 12:40:47 am by SpeCter »

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: What about memory leaks?
« Reply #26 on: June 06, 2015, 01:28:03 am »
I think that pretty much fits what I said ;)

Not even remotely.

It's not an ego thing.  I don't think I'm "better than that" or "too good" to use smart pointers.  If you're interested in what I'm actually saying, just go back and read my posts a little more closely.

On a more meta-level, it's natural for coders to have strong opinions about what works best.  But I think a mistake many more "fanatical" coders make is the "my way is the best and only way" standpoint.

Let me give an example.  Here's a great video worth watching for anyone who programs games:

CppCon 2014: Mike Acton "Data-Oriented Design and C++"

Now, there's some things I find brilliant about Mike's approach to coding games.  And other things I find insane.  You think it's crazy not to use smart pointers?  Mike's general policy on using any STL containers is "no".  (That's insane to me.)

But you know what?

What he's doing is working.  He finishes games.  They're stable.  They're polished.  They're fast.  They're successful.  Would I like to code in that environment?  No.  Do I personally agree with all his code policies?  No.  But I'm not going to say he's doing it wrong, just because he doesn't do things the same way I do. 

« Last Edit: June 06, 2015, 01:30:02 am by Jabberwocky »

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: What about memory leaks?
« Reply #27 on: June 06, 2015, 10:09:32 am »
 :o Looks like a holy war here. =) I think that use of smart or raw (or mix like I do) pointers is a private matter. But, I still think that newbie must begin from raw pointers.

SpeCter

  • Full Member
  • ***
  • Posts: 151
    • View Profile
Re: What about memory leaks?
« Reply #28 on: June 06, 2015, 12:00:52 pm »
There is a reason he and many other engine programmers don't like STL Containers. Lets say you are programming for consoles:
Most STL containers are made to be as generic as possible. This is a good thing, but not especially good for everything. Having limited resources means that you have to find ways to get around that problem. Most STL implementations are not very resource friendly and their memory allocation might not be a good fit for what you do.
I'm not saying you shouldn't use STL containers , to be honest I like them.
I'm also not saying you shouldn't use raw pointers(or that it's wrong), what I'm saying is that you make your life unnecessarily hard if you don't use the tools laid out before you.
Using unique_ptr vs. raw pointer is not a way of saying it's better for me. It is using my arsenal of programming tools in a smart way.
There is no technical reason not to use unique_ptr. It is only a personal matter, be it an ago thing or whatever(I'm not saying you are not using them out of ego!).
Mike Acton has technical reasons for the things he says, thats not insane. Not choosing STL containers if they don't fit the environment they are put in is the right thing to do.

Then again, I can't understand his hate for templates :D

That said I'm putting down my axe to end this "holy war". I wanted to give advice but did it like an arrogant prick in the beginning(and I'm sorry for that). It's just that from a technical point of view unique_ptr is a no-brainer for me.

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: What about memory leaks?
« Reply #29 on: June 06, 2015, 05:21:17 pm »
Appreciate the post, SpeCter.

Most STL implementations are not very resource friendly and their memory allocation might not be a good fit for what you do.

Don't custom memory allocators get you around this problem?

I'm not saying you shouldn't use STL containers , to be honest I like them.
I'm also not saying you shouldn't use raw pointers(or that it's wrong), what I'm saying is that you make your life unnecessarily hard if you don't use the tools laid out before you.

That's a good argument.

There is no technical reason not to use unique_ptr.

As we discussed earlier, a technical case can be made for not using shared_ptr.  But I agree with you on unique_ptr.  I confess it didn't really occur to me to use the one (unique), but not the other (shared). 

That would give you no problems, performance wise.  Stylistically though, it might.  Now you've got a mixture of some pointers which are managed for you (unique_ptr), and some which are not (raw, for anything not suited to a unique_ptr). 

Actually, while I've got a forum filled with smart pointer folks, let me ask a question:

Let's say you've got some class like this:

// "skills" as in RPG-style skills, perhaps combat moves, or other abilities like crafting.
class SkillDirectory
{
public:
   // ... constructors, etc...
   const Skill* LookupSkill(const std::string& i_skillName) const;

private:
   // maps a skill name to a skill class.
   std::map<std::string, Skill*> m_mapSkill;
};
 

The SkillDirectory owns the Skill* memory.  However, it serves out pointers to this memory to other gamesystem code that uses it.  The list of available skills in the game will never change at runtime.  So it is possible for other classes to safely store a pointer to one for the duration of the game. 

So let's say that other classes in the game (perhaps some Entity component relating to known skills) will also want to hold Skill* pointers, rather than skill names or IDs which force a lookup every time you need to access the skill.  Maybe this is done for convenience or performance reasons.

Is there any way to avoid getting around the use of shared_ptr in this scenario?  (Provided you don't want to use raw pointers).
« Last Edit: June 06, 2015, 05:28:28 pm by Jabberwocky »