2

My first question is that the object A(v) that added the the map, it should be deleted automatically when exit the scope?

My second question is what would happen to the object added into the map, when program exits? I believe when I do a_[name] = A(v);, a copy is stored to the map. Also, do I need to provide a copy constructor?

void B::AddA(std::string name, int v) {
    a_[name] = A(v);
}

My last question is that I did not create any object with "new", I shouldn't need to delete any.

I don't understand where the leak come from.

I appreciate any help. Thank you.

full code

#include <map>
#include <string>
#include <iostream>

class A {
    public:
        int vala_;
        A();
        ~A();
        A(int v);
};

A::A() {
    vala_ = 0;
}

A::~A() {}

A::A(int v) {
    vala_ = v;
}


class B {
    public:
        int valb_;
        std::map<std::string, A> a_;
        B();
        ~B();
        void AddA(std::string name, int v);
};

B::B() {
    valb_ = 0;
}

B::~B() {
}

void B::AddA(std::string name, int v) {
    a_[name] = A(v);
}


int main() {
    B b;
    b.AddA("wewe", 5);
    std::cout << b.a_["wewe"].vala_ << std::endl;
    exit(0);
}

valgrind

I replaced the number ==????==, to ==xxxx==. I guess it was the process id. 
==xxxx== Memcheck, a memory error detector
==xxxx== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==xxxx== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==xxxx== Command: ./a.out --leak-check=full -s
==xxxx==
5
==xxxx==
==xxxx== HEAP SUMMARY:
==xxxx==     in use at exit: 72 bytes in 1 blocks
==xxxx==   total heap usage: 3 allocs, 2 frees, 73,800 bytes allocated
==xxxx==
==xxxx== LEAK SUMMARY:
==xxxx==    definitely lost: 0 bytes in 0 blocks
==xxxx==    indirectly lost: 0 bytes in 0 blocks
==xxxx==      possibly lost: 0 bytes in 0 blocks
==xxxx==    still reachable: 72 bytes in 1 blocks
==xxxx==         suppressed: 0 bytes in 0 blocks
==xxxx== Rerun with --leak-check=full to see details of leaked memory
==xxxx==
==xxxx== For lists of detected and suppressed errors, rerun with: -s
==xxxx== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

2 Answers2

5
==xxxx==     in use at exit: 72 bytes in 1 blocks

==xxxx==    still reachable: 72 bytes in 1 blocks

These only mean that when the program exited there was still live memory for which you still had references. The memory wasn't lost completely, which is what normally is referred to as memory leak in the strict sense and would be listed under definitely lost or indirectly lost and possibly lost. When the program ends it doesn't really matter whether there is still unfreed memory.

However, this can still be a sign of a problem, for example if objects that should be destroyed and have destructors with side effects are not run.

In your case the problem is the exit(0) call. Calling std::exit ends the program right there with some cleanup. Cleanup includes destruction of objects with static storage duration, but not objects with automatic storage duration that would normally be destroyed when their scope is left.

In your case B b;, including all the elements it stores, would normally be destroyed at the } or return statement of main, but because you call exit beforehand, it will never be destroyed. In this particular situation that is not a problem, but if e.g. b was an object with destructor that is supposed to perform some operations with side-effect visible outside the program, it might be.

You should not call exit(0) to exit the program from main. Just use return 0; or leave it out entirely, because for main specifically no return statement is equivalent to return 0;.


Sidenote: You shouldn't explicitly declare/define destructors that don't do anything and aren't virtual, such as A::~A() {}. If you don't declare a destructor at all in the class, the compiler will generate this for you automatically and will behave exactly the same.

Declaring the destructor manually anyway has consequences for other implicit generation of special member functions, that may impact the peformance of the program and it also makes it more difficult to consistently follow the rule of 0/3/5.


My first question is that the object A(v) that added the the map, it should be deleted automatically when exit the scope?

A(v) is a temporary object and will be destroyed at the end of the full expression a_[name] = A(v).

Also, do I need to provide a copy constructor?

No, one is implicitly declared by the compiler if you don't declare one manually (same as with the destructor) and it will be defined to simply copy each member, assuming that this is possible. This is usually what you want anyway.

My last question is that I did not create any object with "new", I shouldn't need to delete any.

Yes, that is exactly correct.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • *You shouldn't explicitly declare/define destructors that don't do anything and aren't virtual, such as A::~A() {}* -- Or declare the destructor as `= default;`. – PaulMcKenzie Jan 08 '22 at 23:23
  • @PaulMcKenzie Even declaring and defaulting it, still inhibits the implicit move constructor/assignment, which I think would be confusing: https://godbolt.org/z/Mrd3YG878 But that makes of course sense if all the other special member functions are explicitly defaulted/deleted as well. – user17732522 Jan 08 '22 at 23:28
0

"still reachable" does not strictly mean it is memory leak. I belive it is because you called exit(0) instead of just returning 0. The stack didn't get cleaned up because the program got terminated with signal.

rgnt
  • 551
  • 2
  • 7