1

I was reading this question, and here the jsoncpp CharReaderBuilder::newCharReader() function returns a pointer to a dynamically created CharReader object, which can then be used to parse a JSON.

I understand in that question the OP should have freed the returned pointer once it was used, since it was created on the heap. But, I am confused about whether, if we never store the returned pointer since it is for 1-time-use only, and write something like this:

Json::Value root;
Json::CharReaderBuilder().newCharReader()->parse(serverResponse.response,
    serverResponse.response + serverResponse.size - 1, &root, &Json::String());

Will this still cause a memory leak? If so, then in this case, I am not storing the pointer, so I cannot really call free() or delete to free that location of memory since I need a reference for that.

I guess I could somehow wrap the entire thing around the C++ unique_ptr thing, but I think this should not cause any memory leak. Am I correct?

Edit: From the comments, it seems this will still cause a memory leak. So, how should I delete this pointer since I currently have no reference to it? Am I forced to create a reference and store the pointer if I want to avoid a memory leak? Is there no other way?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 5
    An object that was created with `new` must be freed with `delete`. If it doesn’t get deleted it’s leaked. – Pete Becker Aug 25 '22 at 22:16
  • @PeteBecker but what if I don't have the reference to that object? How am I going to free it? – Chandrachur Mukherjee Aug 25 '22 at 22:16
  • 2
    @ChandrachurMukherjee You have yourself a memory leak! – George Aug 25 '22 at 22:18
  • @George so I must store the returned value otherwise I wont be able to delete it, and if I dont store the returned value then it is impossible to avoid memory leak? – Chandrachur Mukherjee Aug 25 '22 at 22:19
  • Finding a lost object is hard, hard work. If you know the object must be manually managed, keep the pointer. There is no other workable option. – user4581301 Aug 25 '22 at 22:23
  • Alternatively, use smart pointers. :) – Chris Aug 25 '22 at 22:23
  • @Chris, K got it, I would use smart pointers then. Sounds like my best option. I really dont want to write a line storing the pointer when I know it is just one time use anyways. – Chandrachur Mukherjee Aug 25 '22 at 22:24
  • Impossible is a strong word, but for all intents and purposes - yes. – George Aug 25 '22 at 22:24
  • Something like `std::unique_ptr Json::CharReaderBuilder::newCharReader() const` would be an improvement. You can't do that without tweaking the library, so pop the object in a `unique_ptr` as fast as you can after getting it. – user4581301 Aug 25 '22 at 22:28
  • Logic says that, if you have no reference/pointer to an object that has been created with `new`, then you can't `delete` it, so have a memory leak. That means, to avoid a leak, your program must somehow keep track of the object. But it is not the lack of pointer/reference that causes the leak - it is the fact it is not released. It is also possible to have a leak even if your code has a pointer/reference to the object, if code neglects to release it. – Peter Aug 25 '22 at 23:55

2 Answers2

3

"The other way" is using smart pointers. Consider the following examples.

#include <iostream>

struct A {
    int b;
  
    A(int _b) :b(_b) { std::cout << "A created." << std::endl; }
    ~A() { std::cout << "A destroyed." << std::endl; }
};

void c(A *a) {
    std::cout << a->b << std::endl; 
}

int main() {
    c(new A(42));

    return 0;
}

Running this:

% ./a.out
A created.
42

That temporary object created is never cleaned up.

#include <iostream>
#include <memory>

struct A {
    int b;
  
    A(int _b) :b(_b) { std::cout << "A created." << std::endl; }
    ~A() { std::cout << "A destroyed." << std::endl; }
};

void c(std::unique_ptr<A> a) {
    std::cout << a->b << std::endl; 
}

int main() {
    c(std::make_unique<A>(27));

    return 0;
}

Here we've use a smart pointer (std::unique_ptr), and we can see that the destructor is called and the temporary is cleaned up.

% ./a.out
A created.
27
A destroyed.
Chris
  • 26,361
  • 5
  • 21
  • 42
2

Will this still cause a memory leak?

Yes. The returned pointer is pointing at a new'ed object, so it must be delete'd when you are done using the object.

Am I forced to create a reference and store the pointer if I want to avoid a memory leak?

Yes, eg:

CharReader *reader = Json::CharReaderBuilder().newCharReader();
reader->parse(...);
delete reader;

Which can be wrapped in std::unique_ptr so you don't have to delete it manually, eg:

std::unique_ptr<CharReader> reader(Json::CharReaderBuilder().newCharReader());
reader->parse(...);

Alternatively, for a one-time use, you can use operator-> directly on a temporary unique_ptr instance, eg:

std::unique_ptr<CharReader>(Json::CharReaderBuilder().newCharReader())->parse(...);

Either way, consider using an alias to make the code a little more readable, eg:

using CharReader_ptr = std::unique_ptr<CharReader>;

...

CharReader_ptr reader(Json::CharReaderBuilder().newCharReader());
reader->parse(...);

...

CharReader_ptr(Json::CharReaderBuilder().newCharReader())->parse(...);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770