We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

How to handle pointers to pointers C++

atomicgs12
atomicgs12 asked
on
Medium Priority
432 Views
Last Modified: 2012-05-11
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
Comment
Watch Question

Senior Engineer
CERTIFIED EXPERT
Top Expert 2010
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
CERTIFIED EXPERT
Top Expert 2009

Commented:
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

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

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

CERTIFIED EXPERT
Top Expert 2016

Commented:
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
CERTIFIED EXPERT
Top Expert 2009

Commented:
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.
Todd GerbertSenior Engineer
CERTIFIED EXPERT
Top Expert 2010

Commented:
Hmm, perhaps I read the question too literally. ;)

Author

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?
Todd GerbertSenior Engineer
CERTIFIED EXPERT
Top Expert 2010

Commented:
Then in that case, yup, delete [] pInBuff. Though I do like Infinity's comment.

Author

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
Todd GerbertSenior Engineer
CERTIFIED EXPERT
Top Expert 2010

Commented:
a: std::wstring

b: the caller can control the lifetime of the data by controlling the scope of the object
CERTIFIED EXPERT
Top Expert 2009

Commented:
>> 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.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.