SFML community forums

Help => General => Topic started by: freekill on June 03, 2015, 12:40:36 pm

Title: What about memory leaks?
Post by: freekill on June 03, 2015, 12:40:36 pm
Hi!

I have problem, with memory leaks.

I created medium project, when I notice that i had many memory leaks...
Iam deallocating all memory, but mem leaks are still.

I try to google it, and I tried with easy example with Creating window.

This code also have memory leaks.

#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <SFML/Graphics.hpp>

using namespace sf;
int main()
{
        sf::RenderWindow App(sf::VideoMode(640, 480), "Leak");
        sf::Event zdarzenie;
        while (App.isOpen())
        {

                while (App.pollEvent(zdarzenie))
                {
                        if (zdarzenie.type == Event::Closed || (zdarzenie.type == Event::KeyPressed && zdarzenie.key.code == Keyboard::Escape))
                        {
                                App.close();
                        }
                        App.clear();
                        App.display();
                }
        }
        _CrtDumpMemoryLeaks();
        return 0;
}

 

Mem leaks:

Detected memory leaks!
Dumping objects ->
{211} normal block at 0x042EB718, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{210} normal block at 0x042EB6D0, 8 bytes long.
 Data: <  FR    > DC 91 46 52 00 00 00 00
{209} normal block at 0x042EB650, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{208} normal block at 0x042EB608, 8 bytes long.
 Data: <h FR    > 68 91 46 52 00 00 00 00
{207} normal block at 0x042EB588, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{206} normal block at 0x042EB540, 8 bytes long.
 Data: <h FR    > 68 8E 46 52 00 00 00 00
{205} normal block at 0x042EB4C0, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{204} normal block at 0x042EB478, 8 bytes long.
 Data: <  FR    > F4 8D 46 52 00 00 00 00
{203} normal block at 0x042EB3F8, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{202} normal block at 0x042EB3B0, 8 bytes long.
 Data: <  FR    > F4 8A 46 52 00 00 00 00
{201} normal block at 0x042EB330, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{200} normal block at 0x042EB2E8, 8 bytes long.
 Data: <  FR    > 80 8A 46 52 00 00 00 00
{199} normal block at 0x042EB268, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{198} normal block at 0x042EB220, 8 bytes long.
 Data: <  FR    > 80 87 46 52 00 00 00 00
{197} normal block at 0x042EB1A0, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{196} normal block at 0x042EB158, 8 bytes long.
 Data: <  FR    > 0C 87 46 52 00 00 00 00
{195} normal block at 0x042EB0D8, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{194} normal block at 0x042EB090, 8 bytes long.
 Data: <  FR    > 0C 84 46 52 00 00 00 00
{193} normal block at 0x042EB010, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{192} normal block at 0x042EAFC8, 8 bytes long.
 Data: <  FR    > 98 83 46 52 00 00 00 00
{191} normal block at 0x042EAF48, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{190} normal block at 0x042EAF00, 8 bytes long.
 Data: <  FR    > 98 80 46 52 00 00 00 00
{189} normal block at 0x042EAE80, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{188} normal block at 0x042EAE38, 8 bytes long.
 Data: <$ FR    > 24 80 46 52 00 00 00 00
{187} normal block at 0x042EADB8, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{186} normal block at 0x042EAD70, 8 bytes long.
 Data: <$}FR    > 24 7D 46 52 00 00 00 00
{185} normal block at 0x042EACF0, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{184} normal block at 0x042EACA8, 8 bytes long.
 Data: < |FR    > B0 7C 46 52 00 00 00 00
{183} normal block at 0x042EAC28, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{182} normal block at 0x042EABE0, 8 bytes long.
 Data: < yFR    > B0 79 46 52 00 00 00 00
{181} normal block at 0x042EAB60, 64 bytes long.
 Data: <N   o       J   > 4E 00 00 00 6F 00 00 00 20 00 00 00 4A 00 00 00
{180} normal block at 0x042EAB18, 8 bytes long.
 Data: <<yFR    > 3C 79 46 52 00 00 00 00
{177} normal block at 0x042EA798, 20 bytes long.
 Data: <8r_ 8r_ 8r_     > 38 72 5F 00 38 72 5F 00 38 72 5F 00 01 00 CD CD
{176} normal block at 0x04208D08, 24 bytes long.
 Data: <X               > 58 F6 10 04 FF FF FF FF 00 00 00 00 00 00 00 00
{175} normal block at 0x03E7F7E8, 40 bytes long.
 Data: <  FR            > 20 12 46 52 10 00 00 00 00 00 00 00 00 00 00 00
{173} normal block at 0x005F2D08, 40 bytes long.
 Data: <  FR            > 20 12 46 52 10 00 00 00 00 00 00 00 00 00 00 00
{152} normal block at 0x005F7540, 24 bytes long.
 Data: <xu_             > 78 75 5F 00 FF FF FF FF 00 00 00 00 00 00 00 00
{151} normal block at 0x005F74B0, 24 bytes long.
 Data: < t_             > E8 74 5F 00 FF FF FF FF 00 00 00 00 00 00 00 00
{149} normal block at 0x005F7360, 24 bytes long.
 Data: < s_             > 98 73 5F 00 FF FF FF FF 00 00 00 00 00 00 00 00
{148} normal block at 0x005F72D0, 24 bytes long.
 Data: < s_             > 08 73 5F 00 FF FF FF FF 00 00 00 00 00 00 00 00
{147} normal block at 0x005F7288, 8 bytes long.
 Data: < vFR    > 14 76 46 52 00 00 00 00
{146} normal block at 0x005F7238, 20 bytes long.
 Data: <  .   .   .     > 98 A7 2E 04 98 A7 2E 04 98 A7 2E 04 01 01 CD CD
{145} normal block at 0x005F71F8, 4 bytes long.
 Data: <    > 0D 00 00 00
{144} normal block at 0x005F71B8, 4 bytes long.
 Data: <    > 0C 00 00 00
Object dump complete.
 
I updated my graphic drivers to the latest version, but it didnt help.

My graphic card is RADEON HD 7770.
Title: Re: What about memory leaks?
Post by: ChronicRat on June 03, 2015, 05:39:24 pm
This is incorrect. You list leaks when your objects are alive.
Use this code in the very begining:
// enable memleak detection
#if defined(_DEBUG) && defined(WINDOWS)
        int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
        tmpFlag |= _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF;  // Check heap alloc and dump mem leaks at exit
        _CrtSetDbgFlag( tmpFlag );
        assert( !errno );
        //_crtBreakAlloc = 101;
#endif
 
This will autmatically list all the leaks on program exit.
Title: Re: What about memory leaks?
Post by: freekill on June 03, 2015, 05:50:16 pm
Hmm i use this method to detect leaks :

https://msdn.microsoft.com/pl-pl/library/x98tx3cf.aspx

I tried your method, but it didnt list leaks:



#if defined(_DEBUG) && defined(WINDOWS)
int tmpFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
tmpFlag |= _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF;  // Check heap alloc and dump mem leaks at exit
_CrtSetDbgFlag(tmpFlag);
assert(!errno);
_crtBreakAlloc = 101; // or //_crtBreakAlloc
#endif
#include <stdlib.h>
#include <crtdbg.h>
#include <vector>
#include <SFML/Graphics.hpp>
using namespace sf;
using namespace std;
class A
{
private:
        int a;
public:
        A(int _a)
        {
                a = _a;
        }
};

int main()
{
        vector <A*> vec;
        A *ob;

        ob = new A(4);
        vec.push_back(ob);
        sf::RenderWindow App(sf::VideoMode(640, 480), "Leak");
        sf::Event zdarzenie;
        while (App.isOpen())
        {

                while (App.pollEvent(zdarzenie))
                {
                        if (zdarzenie.type == Event::Closed || (zdarzenie.type == Event::KeyPressed && zdarzenie.key.code == Keyboard::Escape))
                        {
                                App.close();
                        }
                        App.clear();
                        App.display();
                }
        }

        return 0;
}
 


What do i wrong?
Title: AW: What about memory leaks?
Post by: eXpl0it3r on June 03, 2015, 05:56:46 pm
At best you learn about RAII and smart pointers and stop worrying about memory leaks.

SFML uses internally some global states which only get deleted when the application exits. So if you really must, check that your tool takes that into consideration.
Title: Re: What about memory leaks?
Post by: ChronicRat on June 03, 2015, 06:23:02 pm
In the very begining of "main" function! =) And it won't list leaks because your code hasn't them.
Title: Re: AW: What about memory leaks?
Post by: ChronicRat on June 03, 2015, 06:26:29 pm
At best you learn about RAII and smart pointers and stop worrying about memory leaks.
I think that newbie programmer must avoid use of smart pointers - he has to understand what they do. But he can read about RAII, sure.
Title: Re: What about memory leaks?
Post by: ChronicRat on June 03, 2015, 06:28:35 pm
And change
#if defined(_DEBUG) && defined(WINDOWS)
to
#ifdef _DEBUG
I'm sure that you have no WINDOWS definition.
Title: Re: What about memory leaks?
Post by: freekill on June 03, 2015, 07:22:19 pm
And it won't list leaks because your code hasn't them.

I dont delete objects from vector, so it should be leak there...

And change
#if defined(_DEBUG) && defined(WINDOWS)
to
#ifdef _DEBUG
I'm sure that you have no WINDOWS definition.

It dont work.

Can you type the finally version?
Title: Re: What about memory leaks?
Post by: Jesper Juhl on June 03, 2015, 07:49:43 pm
I dont delete objects from vector, so it should be leak there...
True. You store raw pointers to heap allocated objects in your vector which the vector won't delete when it is destroyed (it would if they had been std::unique_ptr's instead), so you are technically leaking them when the program terminates.
But unless the destructors of the objects allocated on the heap actually have important jobs to do at process termination time, then this theoretical "leak" is completely without consequence, since as soon as your program exits the operating system kernel will reclaim all memory (and other resources) that the program allocated.
Actually, "leaking" objects on purpose when terminating an application is a well known optimization trick to shut down faster by bypassing destructors if it is known that they don't do any work that is persistent between runs of the application (not that I'm advocating that one does that without good reason and full knowledge of the consequences; I'm just pointing out that it's a well known technique).

So, in a nutshell: if you do this in main:
new char(1024*1024*1024);
and then return from main, then yes, you technically leak 1 gigabyte, but that leak only lasts milliseconds until the program is gone and the kernel has reclaimed the memory. It's not like that gigabyte is now lost forever.
Title: Re: What about memory leaks?
Post by: ChronicRat on June 03, 2015, 08:22:25 pm
I dont delete objects from vector, so it should be leak there...
Yep, I didn't noticed it. So, there is only one thing left - you are not in DEBUG mode.
Title: Re: What about memory leaks?
Post by: freekill on June 03, 2015, 09:27:45 pm
Yep, I didn't noticed it. So, there is only one thing left - you are not in DEBUG mode.

(http://i.imgur.com/HqB8Zbq.png)


oh wait i delete that underlined, and after that it show mem leak.


It helps. TY all for replies. Close topic. I dont have any Mem leak in my project :) now im sure.
Title: Re: What about memory leaks?
Post by: ChronicRat on June 03, 2015, 10:17:47 pm
Comment _crtBreakAlloc or you will get break point on this allocation.
For example you have this leak:
{195} normal block at 0x042EB0D8, 64 bytes long.
By setting _crtBreakAlloc to 195 program will stop in the line of allocation. Very useful thing, but not always can help (50/50).
Title: Re: AW: What about memory leaks?
Post by: eXpl0it3r on June 03, 2015, 11:16:04 pm
I think that newbie programmer must avoid use of smart pointers - he has to understand what they do. But he can read about RAII, sure.
Well I disagree. You can learn modern C++ without having to learn C or "old" C++. The memory model can equally well be taught with smart pointers. ;)
Title: Re: What about memory leaks?
Post by: Jesper Juhl on June 04, 2015, 12:05:26 am
I agree 100% !
Title: Re: AW: What about memory leaks?
Post by: Jabberwocky on June 05, 2015, 07:03:00 pm
At best you learn about RAII and smart pointers and stop worrying about memory leaks.

I've noticed a few SFML team members are huge advocates of smart pointers.  Enough so, that I've spent some time reevaluating my own decision to avoid their use in my current game project.  I wondered if maybe I was just entrenched in my ways, and resisting change for no good reason.  "I've always done it this way (raw pointers), and it works" kind of thing.  I even did some research on the performance of raw pointers over smart pointers, hoping to find some smoking gun which would justify my use of raw pointers, but that didn't stick.  There is some small performance gain, but certainly not enough to justify ignoring smart pointers altogether.

Here's what I've finally come up with.  Using raw pointers is certainly more dangerous.  But I find that danger forces me to think more carefully about memory management and ownership in my code.  I can feel some eyes rolling as I type that.  But here's an analogy which maybe you can get behind.  A big reason I choose something like SFML over Unity is that I am forced down an inefficient and more "dangerous" route in creating my game.  I'm working closer to the metal.  I'm intentionally taking the harder path in order to shape my code, and my game in a precise fashion. 

Let's say you wanted a model ship.  You could either build it yourself, at a ridiculous cost-benefit ratio, or buy one for cheap.  But there is value in the building of it, even if it crashes (heh) down on you 10 times before you get it right.  Once you do get it right, it is a thing of beauty; you know every timber, every nail, every knot of that model ship.

That's how I feel about using raw pointers.  I have the "luxury" of being the only coder on my project, so it's less likely some noob junior programmer is going to walk in and trash the place.  Because of reasons like that, I would never argue against using smart pointers.  It certainly makes your code more robust to bad programming habits and errors.  But I think there is a case to be made for avoiding them, too.  It's not like before the advent of c++11, boost, and smart pointers all software was buggy crap.  It just took a little more finesse and expertise to make it work.

I may change my tune on this in the future.  But I figured I'd share my thoughts on smart pointers as of today.
Title: Re: What about memory leaks?
Post by: Rosme 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.
Title: Re: What about memory leaks?
Post by: Jesper Juhl 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);
:)
Title: Re: What about memory leaks?
Post by: Rosme on June 05, 2015, 08:46:56 pm
Oh yes for sure :) I just didn't put auto for clarification
Title: Re: What about memory leaks?
Post by: Jabberwocky 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.

Title: Re: What about memory leaks?
Post by: Rosme 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.
Title: Re: What about memory leaks?
Post by: Jabberwocky 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.
Title: Re: What about memory leaks?
Post by: SpeCter 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.
Title: Re: What about memory leaks?
Post by: Jabberwocky 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.
Title: Re: What about memory leaks?
Post by: SpeCter 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.
Title: Re: What about memory leaks?
Post by: Jabberwocky 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?
Title: Re: What about memory leaks?
Post by: SpeCter 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)
Title: Re: What about memory leaks?
Post by: Jabberwocky 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++"  (https://www.youtube.com/watch?v=rX0ItVEVjHc)

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. 

Title: Re: What about memory leaks?
Post by: ChronicRat 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.
Title: Re: What about memory leaks?
Post by: SpeCter 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.
Title: Re: What about memory leaks?
Post by: Jabberwocky 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).
Title: Re: What about memory leaks?
Post by: SpeCter on June 06, 2015, 05:30:51 pm
You could store an unique_ptr inside your map and return your raw pointer to whatever needs it.
The only difference is that you don't have to call delete yourself, SkillDirectory will do that for you the moment it leaves its scope.(Or to be more correct unique_ptr will do it because it leaves its scope)
The other classes can use the raw pointer like before but it is not their responsibility to delete the memory thats SkillDirectory's task and that will happen when you decide that its lifetime is over.
This would be a mix like ChronicRat said.

RAII to the rescue ;D
Title: Re: What about memory leaks?
Post by: Jesper Juhl on June 06, 2015, 05:37:57 pm
As I see it it's very simple.
When you are dealing with single ownership use unique_ptr since it offers many advantages over raw pointers and has zero overhead.
When you are dealing with shared ownership then shared_ptr is the obvious choice.
Only when you are dealing with non-owning pointers (or interfacing with C or legacy APIs) do raw pointers still make sense in a modern C++14 universe.
Title: Re: What about memory leaks?
Post by: Jabberwocky on June 06, 2015, 06:00:42 pm
You could store an unique_ptr inside your map and return your raw pointer to whatever needs it.

That makes sense to me. 
I expected there would be more resistance to storing a secondary raw pointer to a unique pointer (edit - sounds like Jesper would be against this approach).  It's not really "unique" then.  But agree in this case it would work.

RAII to the rescue ;D
I'm not totally sure how much in need of rescuing the pure raw pointer case needs.   :P  You're basically trading a single destructor loop, for some more complicated pointer syntax.  But I appreciate your thoughts!  The unique_ptr implementation is completely reasonable to me.
Title: Re: What about memory leaks?
Post by: SpeCter on June 06, 2015, 06:05:55 pm
It is unique, not in the sense that there is only one pointer pointing to an object though. Its name comes from the fact that it is the only thing owning whatever it points to.
unique_ptr and shared_ptr are only for ownership semantics, who owns the memory and who is responsible for releasing it.
Title: Re: What about memory leaks?
Post by: Jabberwocky on June 06, 2015, 06:19:28 pm
Fully agreed, SpeCter.

I suspect some coders might be against it, solely because, in general, storing a raw pointer to another unique pointer creates a possible dangling pointer scenario.  Whereas it wouldn't if you used shared pointers. 

But yeah, there's no more "dangle danger" with the unique_ptr implementation than a pure raw pointer implementation.  And of course, part of the problem description is that these pointers would never go out of scope until game shutdown.
Title: Re: What about memory leaks?
Post by: SpeCter on June 06, 2015, 06:27:39 pm
I don't understand what you mean with raw pointer to another unique pointer, could you make an example for me please?
Title: Re: What about memory leaks?
Post by: Rosme on June 06, 2015, 06:34:57 pm
The issue now seems more to be on what people understand is unique_ptr. Some believe that means it is unique and it is the only place it should be. That is not the case. unique_ptr means unique ownership. Having a naked raw pointer obtain by unique_ptr::get() is fine, as long as the original owner of the unique_ptr does not go out of scope thus invalidating the raw pointer.
Title: Re: What about memory leaks?
Post by: Jabberwocky on June 06, 2015, 06:56:16 pm
I don't understand what you mean with raw pointer to another unique pointer, could you make an example for me please?

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, std::unique_ptr<Skill*>> m_mapSkill;
};

const Skill* SkillDirectory::LookupSkill(const std::string& i_skillName) const
{
   // my syntax here is probably wrong because I don't use smart pointers, but...
   std::map<std::string, std::unique_ptr<Skill*>>::const_iterator it = m_mapSkill.find(i_skillName);

   if (it != m_mapSkill.end())
   {
      // return a raw pointer to the std::unique_ptr
      return (*it)->get();
   }
   return 0;
}
 

And some other gamesystem code stores this raw Skill* pointer like so:

bool PlayerSkills::AddSkill(const std::string& i_skillName)
{
   const Skill* pSkill = GetSkillDirectory()->Lookup(i_skillName);
   if (!pSkill)
   {
       // handle error..
       return false;
   }

   // Track this RAW SKILL POINTER in my "known skills" data.
   m_setKnownSkill.insert(pSkill);
   // So now the SkillDirectory has a unique_ptr to pSkill, and I have a raw pointer to pSkill.
}
 
Title: Re: What about memory leaks?
Post by: SpeCter on June 06, 2015, 07:19:17 pm
Ah ok.
2 things to note here:
1. unique_ptr<Skill> instead of unique_ptr<Skill*>
2. without starting another war here, you should probably use null_ptr instead of 0 (or NULL)

As long as SkillDirectory doesn't get deleted there shouldn't be a problem.

Title: Re: What about memory leaks?
Post by: Jabberwocky on June 06, 2015, 08:17:12 pm
Cool, so we're on the same page.
Title: Re: What about memory leaks?
Post by: Mörkö on June 06, 2015, 09:31:57 pm
I too avoid smart pointers. Part of the reason is something Jonathan Blow said—one of very few things I agree with him about—namely that smart pointers changes the type of the object and that's not good. Illustration:

auto ptr = new Object{};
This is very easy to understand. `ptr` is simply the address of my object. The possible operations are also very limited (which is a good thing for stupid programmers like me). Passing it around is straight forward, and so is dereferencing it and performing arithmetic on it in those special cases. I feel like the object I'm handling is small and easy to understand.

auto ptr = std::unique_ptr<Object>(new Object{});
Now the type of the object has changed. It's no longer merely an address to my object, or even my object, but now I have an object of type "std::unique_ptr<..." which is something else than what I wanted. The new object I actually want sort of hidden somewhere inside it, both in terms of how unique_ptr works, and literally by how the declaration reads.

This increases the complexity of the program, because now I have to reason about how std::unique_ptr will act in addition to everything else. Mind you, this doesn't even absolve me from thinking about the lifetime of the object, it merely hides deallocation into the rules of scope instead of having me handle it explicitly. The reason why I use C++ is because I want to do memory management manually, if I wanted memory to be handled in automatic and hidden ways I would just a GC'd language instead.

I enjoy doing things explicitly, because that makes it easier for me to understand the meaning of my code. Someone may argue that smart pointers are actually super simple to understand, and if that's how you feel, then go ahead. However, if you are double freeing your pointers or forgetting to free them, or often trying to access freed memory, well I believe you have problems that smart pointers aren't going to solve. And like Jabberwocky said, if something like allocation fails then smart pointers aren't likely going to save you either.
Title: Re: What about memory leaks?
Post by: Rosme on June 06, 2015, 11:31:44 pm
You clearly didn't read correctly all we said. Also, I don't get why you say it changes everything? unique_ptr offer the same operator(*, ->) to access the underlaying object. In fact, it makes the software more robust, because you are sure you are not going to copy the pointer because it is not copyable. The proof have been made by a lot of very experimented programmers(not only on this forum but across the internet) why smart pointers in general are good. But if you really believe that full manual memory management(because even with smart pointer, there is manual memory management) is really better, than I can't do anything but wait until you have an issue with your pointers. Now, here is another small example of memory leak if you want:

Foo* a = new Foo();
std::vector<Bar> myVector;

//Stuff happens, myVector is filled and is of size 10

auto& b = myVector.at(10); //Throws out_of_range

delete a; //Is never reached
 

Now remember this is a very trivial code, and most useless, but you can (hopefully) get the point. Unless you surround your call to at with try catch of course, you get a memory leak. Truthfully, you'll probably won't use at and use [] which will be UB instead. But you get the point. This is what full memory management can cause. It's problem, over problem. It's tricky and complicated. To fully make sure that there isn't any place where memory can leak, the code will look like world war three went through it. With std::unique_ptr, no worries.
Title: Re: What about memory leaks?
Post by: Jabberwocky on June 07, 2015, 12:03:48 am
Thanks for that, Mörkö.

Actually, I think you wrote your objections more eloquently than I did.

You clearly didn't read correctly all we said.

That isn't clear to me at all from Mörkö's post.  In fact, everything he said is technically correct, as far as I understand.

The proof have been made by a lot of very experimented programmers(not only on this forum but across the internet) why smart pointers in general are good.

I am a very experienced programmer.
Jonathan Blow is a very experienced programmer.
A simple google search lists many who critique them.
Obviously it's not as unanimous as you say.

But if you really believe that full manual memory management(because even with smart pointer, there is manual memory management) is really better, than I can't do anything but wait until you have an issue with your pointers.

Now, here is another small example of memory leak if you want:

There are other ways to find memory leaks in your program that do not involve permanent changes to your code at all.
Examples:
- valgrind (http://valgrind.org/)
- this for visual studio (http://msdn.microsoft.com/en-us/library/e5ewb1h3%28VS.80%29.aspx)

I can't do anything but wait until you have an issue with your pointers.

In my case, I'm afraid you're going to be waiting a long time.  Unless you honestly believe that every C++ program in existence before C++11 was a buggy piece of memory leaking crap (which is obviously not true), your statement doesn't hold.  I'll certainly agree with you if you say smart pointers can make the job of memory management easier for some programmers.  But it's blatantly incorrect to say they are necessary for a proper functioning program.

I do however very much appreciate hearing from folks who use smart pointers.  Maybe someday I'll change, or have to work on a project where they are code standard. 
Title: Re: What about memory leaks?
Post by: Mörkö on June 07, 2015, 02:44:52 am
You clearly didn't read correctly all we said. Also, I don't get why you say it changes everything? unique_ptr offer the same operator(*, ->) to access the underlaying object. In fact, it makes the software more robust, because you are sure you are not going to copy the pointer because it is not copyable.
It does change the type of the object. Using an object of type std::unique_ptr instead of simply (the address of) the object brings in a whole bunch of new rules and functionality which requires programmer attention. Just because it shares two of the operators doesn't change that fact.

About copying the pointer, see what I said about accessing freed memory. In that scenario you have written a program which you don't understand. Not being able to effectively reason about your own code is not a problem that smart pointers are going to solve, yes they might sweep some of the symptoms under the rug but they will not fix the underlying issue.

Quote
Now, here is another small example of memory leak if you want:

------ snipped ------

Now remember this is a very trivial code, and most useless, but you can (hopefully) get the point. Unless you surround your call to at with try catch of course, you get a memory leak. Truthfully, you'll probably won't use at and use [] which will be UB instead. But you get the point.
Why would you not wrap the thing that can throw in try/catch? Just exactly where is the catching clause located in the scenario you propose? If you don't catch it then it won't matter whether memory leaked. Your example doesn't have anything to do with smart pointers. I want to see some examples of robust and elegant code (i.e. doesn't look like ww3 went through it) where you use smart pointers for everything and let exceptions affect control flow in a major way.

Quote
This is what full memory management can cause. It's problem, over problem. It's tricky and complicated.
It's tricky (like programming generally), but I don't think it's complicated. Adding rules and functionality is what makes a program complicated, and that's what smart pointers do. They don't change the fundamental mechanism, they merely hide it behind another mechanism. Note that I am not denying they have any use at all, of course they do, but the trade-off in terms of complexity vs potential benefits is not worth it for me.
Title: Re: What about memory leaks?
Post by: Mörkö on June 07, 2015, 02:55:03 am
In my case, I'm afraid you're going to be waiting a long time.  Unless you honestly believe that every C++ program in existence before C++11 was a buggy piece of memory leaking crap (which is obviously not true), your statement doesn't hold.
Forget about C++ pre 11, think about plain C! Every C program must be a horrible leaking mess right?

Well I guess there are a significant portion of C++ programmers out there who would answer "YEAH, THAT'S RIGHT" ...but ignoring them I think there is a lot of evidence that low level programming was doing just fine even before smart pointers came along.
Title: Re: What about memory leaks?
Post by: shadowmouse on June 07, 2015, 10:02:28 am
That's a nice bit of reductio ad absurdum there. Waiting until someone makes mistakes by not using smart pointers doesn't mean that everyone who didn't use them made mistakes. It means it is possible and therefore you might make a mistake by not using them. If you want examples of try-catch with memory management look at this http://www.bromeon.ch/articles/raii.html Also, in my experience smart pointers can act exactly as normal pointers and when you're using unique_ptr they have no overhead so I can see no reason not to use them except disliking change. And yes, unique_ptr<int> isn't of type int, but neither is int*. Both use the same operators to access the data they point to but unique_ptr has other functions which can be useful. You can even access the underlying pointer directly if you want to.
Title: Re: What about memory leaks?
Post by: Jabberwocky on June 07, 2015, 12:42:07 pm
That's a nice bit of reductio ad absurdum there.

I think your reductio ad absurdum is a strawman.  ;)
Heh, actually I get why you're saying that, but it's really this simple.

Rosme said this:
Quote
I can't do anything but wait until you have an issue with your pointers.
...obviously implying issues was either likely or practically inevitable.

My response refuted this - that it is neither likely nor practically inevitable.

I'm pretty sure that's all either of us meant.

Waiting until someone makes mistakes by not using smart pointers doesn't mean that everyone who didn't use them made mistakes. It means it is possible and therefore you might make a mistake by not using them.

You can't write a line of C++ code without possibly making a mistake.  Of course mistakes can be made.  All C++ programmers have a toolbox and mental process to address this.  Mine is different than yours.  That doesn't make me incorrect.

shadowmouse, the rest of your post mostly repeats arguments that have already been made, and already responded to.  (I don't blame you for that, it's getting to be a long thread.)  We did give some reasons for not using smart pointers - there's more to it than disliking change.  We did give some reasons why those exception/memory leak examples are not a real issue.  But you'll have to critique that stuff if you want to cover some new ground here, instead of just talking in circles.

Either way, thanks for chiming in!
Title: Re: What about memory leaks?
Post by: shadowmouse on June 07, 2015, 12:47:46 pm
Morko did ask for examples of code involving exceptions so the main point of my post was the link. But I'd still say that waiting until you have a problem means it only really because benficial if you have a problem, which may or may not happen.

EDIT: Also,
Quote
Every C program must be a horrible leaking mess right?
is reductio ad absurdum because it was never said that all programs with smart pointers have mistakes in them and the extrapolation that because smart pointers can stop issues, not having them means there must be issues is illogical.
Title: Re: What about memory leaks?
Post by: Jesper Juhl on June 07, 2015, 03:46:58 pm
I expected there would be more resistance to storing a secondary raw pointer to a unique pointer (edit - sounds like Jesper would be against this approach).  It's not really "unique" then.  But agree in this case it would work.
I wouldn't be opposed to obtaining a raw pointer to a unique_ptr (or rather; a raw pointer to what the unique_ptr points to), not even to passing it around, as long as it is clear that the raw pointer is not owning the resource pointed to, but merely inspecting/using it. It's all about ownership semantics.
Title: Re: What about memory leaks?
Post by: Mörkö on June 07, 2015, 05:06:28 pm
Quote
Every C program must be a horrible leaking mess right?
is reductio ad absurdum because it was never said that all programs with smart pointers have mistakes in them and the extrapolation that because smart pointers can stop issues, not having them means there must be issues is illogical.
That line was a joke, not a serious argument, which is why it should seem absurd if you take it seriously.

Quote
And yes, unique_ptr<int> isn't of type int, but neither is int*. Both use the same operators to access the data they point to but unique_ptr has other functions which can be useful. You can even access the underlying pointer directly if you want to.
That's all true, but the argument here is that it does not merely represent the address of he object, but also brings in a whole bunch of new rules that the programmer must reason about. And also, it changes the memory management mechanism in a way which some of us find undesirable.
Title: Re: What about memory leaks?
Post by: Nexus on June 11, 2015, 03:21:44 pm
There's so much half-knowledge and plain wrong statements in this thread. "Unique pointers have overhead", "using manual memory management is a matter of taste", "exceptions are not a real issue" and so on. Please stop spreading myths. Beginners read this and are misled all the time, contributing to the main reason why most C++ code is still terrible in 2015.

A while ago I compiled a pretty exhaustive list of arguments for RAII. You can read the article here:
www.bromeon.ch/articles/raii.html
Title: Re: What about memory leaks?
Post by: ChronicRat on June 11, 2015, 04:13:16 pm
Thanks, Nexus, great "debriefing".