简体   繁体   中英

Using Smart Pointers

I am working on a legacy C++ app which has the following function,

char* CreateNewString (const char* node)
{
   int len = (int) strlen(node) + 1;
   char * ptr = new char [len];
   strcpy_s(ptr, len, node);
   return ptr;
}

This function is called from many classes in the app and here's an example use case.

char * nodeID = obj.CreateNewString(process->GetNodeID());

The app calls a different process and get a node ID as char pointer and then passes it to CreateNewString function to dynamically allocate memory for a new string.

Nowhere in the app after the above call, it's deleting the memory. From what I observe, there's a definite memory leak here.

I think there're few ways of resolving this issue. But I want to explore using the smart pointers in C++11 first before trying anything else.

What I Tried:

So I came up with following function:

  char* CreateNewString (const char* node) 
  {
       int len = (int) strlen(node) + 1;
       shared_ptr<char> ptr (new char [len](), [](char* p) {delete [] p;});
       strcpy_s(ptr.get(), len, node);
       return ptr.get();
    }

The goal is to keep function signature the same, ie it returns a char pointer, so that I don't have to make changes at all calling places.

The above is not working as ptr is released as it's declared inside the scope of this function.

My goal is to:

  1. Use C++ 11 smart pointers to achieve this with minimum code changes to the existing application.

An alternative way I am aware of is to dynamically initialize array in calling places itself and then delete it before end of that scope. But I want to explore new C++ features before going back to traditional C++ way. BTW, I am not interested in exploring std::string at this point.

You could:

  • return the shared_ptr
  • return a std::string
  • leave everything as it is

Those are your options.

I don't see a way you can have the function return char pointer and still use smart pointers. There could be potential hacks on getting it done, but all of them have overheads and more importantly, unnecessary code. My suggestion is for a simple change on the new function you wrote and then do another even more simpler change at all calling places.

So the function will look like this,

 shared_ptr<char> CreateNewString (const char* node) 
  {
       int len = (int) strlen(node) + 1;
       shared_ptr<char> ptr (new char [len](), [](char* p) {delete [] p;});
       strcpy_s(ptr.get(), len, node);
       return ptr;
  }

And then anywhere it get's called, simply add a .get()

char * nodeID = obj.CreateNewString(process->GetNodeID()).get();

This is kind of a hack, but it will work and you will not have a memory leak. What you can do is add a static vector of smart pointers and then when you call the function you store the pointer in the vector so that it won't go out of scope at the end of the function. That would look like

char* CreateNewString (const char* node) 
{
    std::size_t len = strlen(node) + 1;
    static std::vector<std::unique_ptr<char[]>> data_pool; // static pool, destroyed at end of program
    data_pool.push_back(std::unique_ptr<char[]>(new char [len]{})); // add pointer to pool
    strcpy_s(data_pool.back().get(), len, node); // copy the string
    return data_pool.back().get(); // return pointer to the managed data
}

using a std::unique_ptr , which deletes arrays correctly so we don't need a custom deleter

Do note that using this solution you wont have a memory leak, but all of the allocated memory will last until the end of the program. You don't gain anything, but at least you are guaranteed the memory is deallocated before the program terminates.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM