5

I am new to C++ and I want to know whether following code is prone to memory leak. Here I am using a std::ostream pointer to redirect output to either console or to a file. For this I am calling new operator for std::ofstream.

#include <iostream>
#include <fstream>

int main() {
    bool bDump;

    std::cout << "bDump bool" << std::endl;
    std::cin >> bDump;

    std::ostream *osPtr;

    if (bDump) {
        osPtr = new std::ofstream("dump.txt");
    } else {
        osPtr = &std::cout;
    }

    *osPtr << "hello";
    return 0;
}

And one more thing, I have not closed the file which I opened while calling constructor for ofstream. Do we have any potential data loss situation here. as file is not closed.

David G
  • 94,763
  • 41
  • 167
  • 253
Apoorva sahay
  • 1,900
  • 3
  • 28
  • 45
  • 1
    Memory leaks don't happen in the main function, unless if you have something like a for/while. – Radu Nov 06 '11 at 05:35
  • 2
    @Radu: Now that depends on your definition of memory leak, now doesn't it? – Dennis Zickefoose Nov 06 '11 at 06:19
  • I believe this is technically undefined behavior: 3.8 [basic.life]/4 "For an object of a class type with a non-trivial destructor, ... if a delete-expression is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior." So by the letter of the standard, when `main` ends if `bDump` is `true` this program could request some shared memory from the OS then end abrupty such that it is never reclaimed, resulting in an actual, permanent memory leak. – Dennis Zickefoose Nov 06 '11 at 06:49
  • @DennisZickefoose: You would be correct that this has undefined behavior if it depends on the side effects produced by the destructor. But it doesn't. And you'd be correct that it would have a memory leak if the destructor released some such resource to the OS. But it doesn't. (So, no it doesn't have a memory leak. No it doesn't have undefined behavior. Yes, this type of of code is *prone* to memory leaks.) – David Schwartz Nov 07 '11 at 17:26
  • @David: Assuming `bdump` is `true`: If the destructor is called, the file "dump.txt" will contain the text "hello". If the destructor is not called, the file "dump.txt" will not contain the text "hello". I agree with you that, in general, leaks like this are not a problem on modern systems. But *only* if the object in question has a trivial destructor... `ofstream` does not qualify. – Dennis Zickefoose Nov 07 '11 at 17:59
  • @DennisZickefoose: I agree that this code is broken if it relies on (or even expects) the side-effects of the destructor. The log may wind up not happening or other things may go wrong. But that's not a *memory leak*. – David Schwartz Nov 07 '11 at 18:56

4 Answers4

7

Yes. Definitely. Any time you call new without delete, there's a memory leak.

After your code has executed, you need to add this:

        if(bDump)
        {
            delete osPtr;
        }
Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • I can't quite agree with this. Definitely there is a problem, and data may be lost unless the file is properly closed or deleted, as suggested. But there is no real "memory" leak, because the reference to the memory allocated is never lost until the end of the execution. In a strict definition, memory leak occurs if a reference to an allocated memory area is unrecoverable lost. – lvella Nov 06 '11 at 06:17
  • 3
    @lvella: And at the end of `main`, the memory is unrecoverably lost. – Dennis Zickefoose Nov 06 '11 at 06:20
  • 1
    You definitely want to use smart pointers here. In the case of an exception you want the destructor to correctly close the stream. – Martin York Nov 06 '11 at 06:23
  • @DennisZickefoose Lost to who? At end of `main` the execution is finished. The stack and all unshared data memory segments used by the process are lost to the (dead) process, but none of them are regarded as leaked resources... – lvella Nov 06 '11 at 06:39
  • 1
    @lvella: Lost to the program, obviously. How do you propose to flush any remaining output without `osPtr` floating around anymore? – Dennis Zickefoose Nov 06 '11 at 06:41
  • 2
    If you don't call the destructor then I would considered the resource leaked. What happens if the object is a link to the space station. I am sure that NASA will be really pissed if you don't cleanly close the connection. – Martin York Nov 06 '11 at 06:42
  • I believe the user posted that code in main() without intending the question to be "is this a leak if used in main()" – Mahmoud Al-Qudsi Nov 06 '11 at 07:59
  • @LokiAstari: The failure to properly shut down an object and a memory leak are totally distinct issues. The only commonality is that failure to call a combination shutdown/free function can cause both problems. But you can have either one alone and they have different symptoms. – David Schwartz Nov 06 '11 at 08:39
  • 1
    @David Schwartz: I am curious on how you call the destructor on a leaked object. Though the issues can be distinct in C++ they are the same as we are dealing with **objects** not plain memory (objects are a resource that can be leaked). Any object that is leaked (as in this case) will not have its destructor called. Thus the resource is leaked. – Martin York Nov 06 '11 at 17:02
5

As @Mahmoud Al-Qudsi mentioned anything you new must also be deleted otherwise it will be leaked.

In most situation you do not want to use delete but rather you want to use a smart pointer to auto-delete the object. This is because in situations with exceptions you could again leak memory (while RAII) the smart pointer will guarantee that the object is deleted and thus the destructor is called.

It is important the at the destructor is called (especially in this case). If you do not call the destructor there is a potential that the not everything in the stream will be flushed to the underlying file.

#include <iostream>
#include <fstream>

int doStuff()
{
    try
    {
        bool bDump;

        std::cout<<"bDump bool"<<std::endl;
        std::cin>>bDump;

        // Smart pointer to store any dynamic object.
        std::auto_ptr<std::ofstream>   osPtr;

        if(bDump)
        {
            // If needed create a file stream
            osPtr.reset(new std::ofstream("dump.txt"));
        } 

        // Create a reference to the correct stream.
        std::ostream&  log = bDump ? *osPtr : std::cout;

        log << "hello";
     }
     catch(...) {throw;}

 } // Smart pointer will correctly delete the fstream if it exists.
   // This makes sure the destructor is called.
   // This is guaranteed even if exceptions are used. 
Martin York
  • 257,169
  • 86
  • 333
  • 562
2

Yes, anything that is newed but never deleteed leaks.

In some cases, it is perfectly reasonable to allocate left right and center, and then just exit, particularly for short-lived batch-style programs, but as a general rule you should delete everything you new and delete[] everything you new[].

Especially in the case above, leaking the object is unsafe, since the object being leaked is an ostream that will never write unflushed content.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • 3
    I really, really don't recommend ever telling people about it being OK to allocate and not delete. That's something that you'll discover on your own when, if, and only you truly need it. – Mahmoud Al-Qudsi Nov 06 '11 at 05:40
  • @MahmoudAl-Qudsi: I agree that it is a hazardous practice that should be used with caution, but I don't agree with shielding developers from reality, especially when it can give them insights into the machinery behind the veil. – Marcelo Cantos Nov 06 '11 at 05:47
  • I understand what you're saying completely - I just feel that certain practices and methods are best discovered by one's self. – Mahmoud Al-Qudsi Nov 06 '11 at 05:50
-1

There is no leak in the code shown. At all times during the execution, all allocated objects are referenceable. There is only a memory leak if an object has been allocated and cannot be referenced in any way.

If the pointer goes out of scope, or its value is changed, without the object being deallocated, that is a memory leak. But so long as the pointer is in the outermost scope and nothing else changes its value, there is no leak.

"In object-oriented programming, a memory leak happens when an object is stored in memory but cannot be accessed by the running code." Wikipedia -- 'Memory leak'

The other answers suggest that any program that uses typical singleton patterns or doesn't free all allocated objects prior to termination has a memory leak. This is, IMO, quite silly. In any event, if you accept that definition, almost every real world program or library has a memory leak, and memory leaks are certainly not all bad.

In a sense, this kind of coding is prone to a memory leak, because it's easy to change the value of the pointer or let it go out of scope. In that case, there is an actual leak. But as shown, there is no leak.

You may have a different problem though: If the destructor has side-effects, not calling it can result in incorrect operation. For example, if you never call the destructor on a buffered output stream writing to a file, the last writes may never actually happen because the buffer didn't get flushed to the file.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • 1
    Not freeing all objects before termination **is** a memory leak, just one most modern OSes clean up for you. It's the memory leak that is occurring in the example code, in fact. In many cases, singletons and other objects are destroyed by the system when the module is unmapped and don't necessarily leak. This answer is mostly incorrect. – ssube Nov 06 '11 at 06:02
  • 1
    In fact, since `osPtr` is going out of scope without the object being deallocated, your definition of memory leak matches what is happening. – ssube Nov 06 '11 at 06:09
  • 1
    I also deemed the answer incorrect at first, but now I think it is correct. Technically, there is a leak, but actually - there isn't. The lifetime of `osPtr ` matches the lifetime of the program, so no actual leak can happen. But still, I think it's a bad coding style. For example, most memory analyzers will report this as a leak. – Violet Giraffe Nov 06 '11 at 06:11
  • 2
    @Alex It is certainly bad style. However, there **is** a leak, the pointer goes out of scope and the memory is lost and never deallocated *by the program*. It's simply a short-lived leak, as the OS steps in to clean up for you. Still a very real leak, and similar code in any other function could cause serious problems. – ssube Nov 06 '11 at 06:18
  • 4
    This is a perfect case of a real leak. At the end the fstream pointer is lost. If it is not deleted then the stream is not closed. If the stream is not closed there is a potential for data not to be flushed to the file. Leaking memory is not really about the memory **it is about the resources not be correctly destroyed** via the destructor. Memory is just the simplest example of a resource but the principle applies to all object allocated in memory. – Martin York Nov 06 '11 at 06:28
  • 1
    Whether you consider this a "memory leak" or not, it is an excellent example of why you shouldn't just rely on the OS reclaiming memory for you. `~ostream` has visible side effects that in general you probably want to have executed. – Dennis Zickefoose Nov 06 '11 at 06:34
  • @peachykeen: The pointer goes out of scope as/after the code returns from main. That terminates the process. The leak doesn't occur when the pointer goes out of scope, it occurs when the user's code runs while having an unreachable object. – David Schwartz Nov 06 '11 at 07:28
  • @LokiAstari: The code is no longer running at the end. Code cannot have a bug that only exists while it is not running. That's simply silly. – David Schwartz Nov 06 '11 at 07:29
  • @peachykeen: There is no distinction between what is done by the program and what the program asks or directs the OS to do. By returning from `main`, exiting the scope (in this case, the last reference on the address space) in which it was allocated, the program releases the reference it held on its address space -- this is no different from destructors implicitly invoked by exiting a scope.. The resources are not destroyed via the destructor, they are destroyed via the process releasing the address space in which they were allocated. – David Schwartz Nov 06 '11 at 07:32
  • By that logic, any code that leaks after running doesn't really have a leak. However, functions can very much leak after they've finished running, including main (the process does not always terminate immediately after return). In the case of a file or stream, the fact this code leaks can be definitely demonstrated. – ssube Nov 06 '11 at 07:34
  • @peachykeen: Code cannot leak "after running". It cannot do anything when it is not running. Functions leak if the process continues normal operation with loss of the ability to access objects allocated by the function but not freed. A memory leak requires three elements -- allocation, loss of ability to reference, resumption of operation. It is definitive if the process could actually repeat the leaking operation multiple times and increase the memory leaked. It is arguable if that is not possible. – David Schwartz Nov 06 '11 at 07:38
  • @David Schwartz: Forgetting to run the destructors before you finish is the silly thing here. The bug is leaking the memory so that the system can not run the destructors. – Martin York Nov 06 '11 at 16:59
  • @LokiAstari: That's not a memory leak though. That's a different type of bug. – David Schwartz Nov 06 '11 at 22:26
  • @ David Schwartz: In what world is this not a memory leak. You original argument was it was a leak just not important because the OS cleaned it up. My argument it is a leak and **ALSO** it is important as it is not just a memory leak but a resource leak. The application lost track of the pointer before the application exited (thus it is a leak). But to be honest at this point I think you are just being a troll. – Martin York Nov 06 '11 at 23:08
  • @LokiAstari: The application lost track of the pointer because it invoked a code path that would immediately release the resource. This is not a memory leak because the application intentionally invokes the OS to clean it up. It is complete and utter nonsense to say that an application that doesn't free all allocate memory IN ITS SHUTDOWN PATH has a memory leak - and that conflicts with the Wikipedia definition. In any event, if you want to argue that, fine. Then almost all real-word code has memory leaks and memory leaks are sometimes bad, sometimes good. This one is harmless. – David Schwartz Nov 07 '11 at 02:49
  • @David Schwartz: Its utter nonsense that you don't understand this. And this id definitely **NOT** harmless. In this case it means the program does not work correctly (as the stream buffer may not be flushed). None of my programs leak memory. Really quoting Wikipedia!!!! This is the weakest part of your argument, – Martin York Nov 07 '11 at 02:53
  • @LokiAstari: If you want to make a reasoned argument, I'm willing to listen. Are you saying any code that doesn't release all allocated memory in its shutdown path has a memory leak? And are you saying all memory leaks are bad? Or are you saying code that doesn't call cleanup functions has a memory leak even if it frees all allocated memory properly because it failed to call cleanup handlers? (Honestly, I don't know what your position is.) – David Schwartz Nov 07 '11 at 02:55
  • @DavidSchwartz: As all my arguments above are good and relatively well explained (and most people agree with them) I can only assume you continue to be a troll. Please feel free to Troll on without me. – Martin York Nov 07 '11 at 03:00
  • @LokiAstari: I can cite dozens of sources that all define a memory leak as exactly what it sounds like -- leaking memory. It has *nothing* to do with errors involving failing to clean up resources other than memory (though the same mistake, failing to invoke combined cleanup/deallocate functions, can cause both problems). [You](http://stackoverflow.com/questions/273209/are-memory-leaks-ever-ok/273232#273232) defined a memory leak as "memory that is allocated and all references to it are lost." (See [here](http://stackoverflow.com/questions/273209/are-memory-leaks-ever-ok/274433#274433)) – David Schwartz Nov 07 '11 at 03:07