Home > Software design >  keeping dynamically allocated memory and vectors post scope in c 11
keeping dynamically allocated memory and vectors post scope in c 11

Time:09-16

I am learning c and came across an issue that I'm not able to resolve. I have read dozens of articles but still not able to figure out the solution. Here are the details: I have created a simple class with two members

uint8_t* atlas;
std::vector<int> vect;

In the constructor of class, I'm allocating memory and initializing the vector like this:

uint8_t* atlas = new uint8_t[512 * 512]();
std::vector<int> vect{ 10, 20, 30 };

Later in another function when accessing these two variables:

std::cout << vect.size() << std::endl;
if(atlas == nullptr) { 
    std::cout << "null atlas" << std::endl;
    return;
} 

The size of the vector is 0 and the atlas is nullptr. After reading several articles about this issue I came across several things such as heap, stack, scope, and smart pointers. The problem is that locally assigned variables are lost as soon as the function or scope ends. My question is that atlas and vect are the members of the class, not locally assigned variables then why the data is getting lost? As per the documentation, the dynamically allocated memory remains intact, it's the pointer that is lost tracking of it.

Several articles suggested that this problem can be solved using smart pointers but I'm not able to figure out, how it can be done. What I need is to keep the dynamically allocated data and vector safe so that I can access them in another function.

CodePudding user response:

Reading dozens of articles does not help if you are not reading about the right thing. Your second code fragment shows initializing local variables, not class members.

class foo
{
public:
    foo()
    {
        // As you have described it, these variables are LOCAL. They overload
        // (and hide) the class members, by defining new variables with the same
        // name.
        uint8_t* atlas = new uint8_t[512 * 512]();
        std::vector<int> vect{ 10, 20, 30 };
    }

private:
    // These will be UNINITIALIZED
    uint8_t* atlas;
    std::vector<int> vect;
};

What's happening above is you have two local variables. The one with manual allocation will leak that memory. The vector will be destroyed when the constructor finishes. In both cases, neither foo::atlas or foo::vect were ever initialized.

Two solutions here. One is to just initialize the variables in the body of the constructor, without creating overloads:

foo()
{
    atlas = new uint8_t[512 * 512]();
    vect.assign({ 10, 20, 30 });
}

The other option is to use the constructor's initializer list:

foo()
    : atlas(new uint8_t[512 * 512]())
    , vect{ 10, 20, 30 }
{
}

Don't forget to clean up your memory with a destructor:

~foo()
{
    delete [] atlas;
}

And, you must also learn about the Rule of Three, since currently it is dangerous (crashy) to copy instances of this class.

Even better, do not manage raw pointers yourself. Use std::vector or smart pointers (i.e. std::unique_ptr / std::shared_ptr)

  • Related