How to handle pointers to pointers C++

I was wondering what is the correct to handle pointers to pointers, that is passing them into a function and delete them on return if the function receiving the pointers creates the memory but does not release it.

Say I have some code as below:
char *pInBuff;

ReturnData(char** pData);

Where ReturnData is defined something like:
ReturnData(&pInBuff)
{
     *pInbuff = new char[128];

     // load pInBuff with data
}

What is proper way to free pInBuff? Is it a simple delete pInbuff, delete [] pInBuff or something else?

Thanks
atomicgs12Asked:
Who is Participating?
 
Todd GerbertIT ConsultantCommented:
Yes, delete [] pInBuff.
0
 
Infinity08Commented:
If you have a function that allocates the memory, I would create a corresponding function in the same compilation unit that de-allocates the memory.

Something like below.


Or better yet : since you're using C++, you could :

(a) make use of SQL data structures like std::string

(b) encapsulate the buffer in a class that has a destructor that takes care of cleaning up the memory automatically

Either of the latter two are preferred over the example below.
void getData(char** pInBuff) {
    *pInbuff = new char[128];

    // load pInBuff with data
}

void cleanData(char** pInBuff) {
    delete [] *pInBuff;
    *pInBuff = 0;
}

// and then :

char* inBuff = 0;
getData(&inBuff);
// use inBuff ...
cleanData(&inBuff);

Open in new window

0
 
OrcbighterCommented:
To make it a little clearer, wrap the whole thing in a class and then pass an instance of the class around


// file MyBuffer.h
class MyBuffer
{
private:
   char* m_buffer = NULL;

protected:
   void Empty();
   
public:
   MyBuffer();
   ~MyBuffer();
   
   void CleanData();
 }

 // file MyBuffer.cpp
MyBuffer::~MyBuffer
{
    Empty();
}

MyBuffer::Empty()
{
    if ( m_buffer != NULL )
    {
        delete [] m_buffer;
        m_buffer = NULL;
    }
}

MyBuffer::CleanData()
{
     Empty();
}

bool MyBuffer::IsEmpty()
{
    return ( m_buffer == NULL )
}

bool MyBuffer::LoadData( const char* data )
{
    bool retStatus = false;
    
    if ( IsEmpty() )
    {
        if ( data != NULL ) && ( strlen( data ) > 0 )
        {
            m_buffer = new char[strlen( data ) + 1];
            retStatus = true;
        }   
    }
    
    return retStatus;
}

// in file using this class

// on stack
{
    MyBuffer buff;
    char* TestData = "This is test data";

    buff.LoadData( TestData);
}

// or on heap
{
    MyBuffer buff = new MyBuffer();
    char* TestData = "This is test data";

    buff->LoadData( TestData);
    delete buff;
}

Open in new window

0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
OrcbighterCommented:
opps a little too quick
last bit should read

// in file using this class

// on stack
{
    bool AllOK = true;
    MyBuffer buff;
    char* TestData = "This is test data";

    ALLOK = buff.LoadData( TestData);
    if ( ALLOK )
    {
        // success
    }
    else
    {
        // error
    }
}

// or on heap
{
    bool AllOK = true;
    MyBuffer buff = new MyBuffer();
    char* TestData = "This is test data";

    AllOK = buff->LoadData( TestData);
    if ( ALLOK )
    {
        // success
    }
    else
    {
        // error
    }

    delete buff;
}

Open in new window

0
 
sarabandeCommented:
why not simply use std::vector?

std::vector<char> v;
getdata(v);
...
void getdata(std::vector<char> & v)
{
    v.resize(128, ' '); // 128 space characters
}

Open in new window


you don't need care for allocation or deallocation yourself. and the called function freely can increase the buffer as needed. and if you need a char* pointer you get it by &v[0] (only if v.size() > 0).

Sara
0
 
Infinity08Commented:
Wow - just noticed a typo in my previous post :

>> (a) make use of SQL data structures like std::string

STL of course, not SQL hehe.
0
 
Todd GerbertIT ConsultantCommented:
Hmm, perhaps I read the question too literally. ;)
0
 
atomicgs12Author Commented:
tgerbert - Are you second quessing yourself? I appreciate all the cool solutions from everyone but I was just looking for something simple and straight forward.

delete [] pInBuff; should be fine, yes?
0
 
Todd GerbertIT ConsultantCommented:
Then in that case, yup, delete [] pInBuff. Though I do like Infinity's comment.
0
 
atomicgs12Author Commented:
as per Infinity's solution:
a. I need this to be Unicode so std:string is out
b. The user may what to keep the data around even after the object that allocated it is destroyed

Thanks to all
0
 
Todd GerbertIT ConsultantCommented:
a: std::wstring

b: the caller can control the lifetime of the data by controlling the scope of the object
0
 
Infinity08Commented:
>> a. I need this to be Unicode so std:string is out

Your current approach of using a char* would be out too ;)
This remark also doesn't invalidate the point I was trying to make ... which was that you have several options that are better than your current approach. One of them is to use an existing solution (whether that be std::string or something else).


>> b. The user may what to keep the data around even after the object that allocated it is destroyed

As tgerbert said : if you want to keep the object, then keep it - nothing is forcing you to clean up the object at any other time than the time that you choose.
The point of encapsulating the buffer in a class, is to make your life easier, by hiding the memory allocation details from the calling code.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.