liv2hak
liv2hak

Reputation: 15010

C struct with a pointer to be wrapped in a unique_ptr

I have a memory struct as shown below.

struct memoryStruct {
    uint8_t* memory;
    size_t size;
};

My code requires me to call free(memory) at multiple places in my code. To avoid this scenario I am thinking of wrapping it in a unique_ptr.

I have the following

struct memoryStruct {
    uint8_t* memory;
    size_t size;
};

struct memoryStructDeleter {
    void operator()(memoryStruct* p) const
    {
        free(p);
    }
};

How do I initialize m_chunk shown below. I want to allocate a memory of size using malloc to memory field and update size accordingly.

std::unique_ptr<memoryStruct> m_chunk;

Upvotes: 0

Views: 979

Answers (2)

n314159
n314159

Reputation: 5095

Assuming you cannot change the struct at all (you should, if you can) and you only want to call malloc and free and not new and delete (which are superior), you can do the following:

struct memoryStructDeleter {
    void operator()(memoryStruct* p) const
    {
        if (p) {
            if (p->memory) {
                 free(p->memory);
            }
            free(p);
        }
    }
};

std::unique_ptr<memoryStruct, memoryStructDeleter> create(size_t s) {
    std::unique_ptr<memoryStruct, memoryStructDeleter> ret(static_cast<memoryStruct*>(malloc(sizeof(memoryStruct))));
    if (!ret) {
        return nullptr;
    }
    ret->memory = static_cast<uint8_t*>(malloc(s * sizeof(uint8_t)));
    if (ret->memory) {
        return ret;
    } else {
        return nullptr;
    }
}

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 597111

You would need something like this:

struct memoryStruct {
    uint8_t* memory;
    size_t size;
};

struct memoryStructDeleter {
    void operator()(memoryStruct* p) const
    {
        if (p) {
            free(p->memory);
            free(p);
        }
    }
};

...

std::unique_ptr<memoryStruct, memoryStructDeleter> m_chunk( static_cast<memoryStruct*>(std::malloc(sizeof(memoryStruct))) );
if (m_chunk) {
    m_chunk->size = DesiredSize;
    m_chunk->memory = static_cast<uint8_t*>(std::malloc(m_chunk->size));
}

Which can be greatly simplified if you get rid of malloc() altogether and use new/new[] or std::make_unique() instead:

struct memoryStruct {
    std::unique_ptr<uint8_t[]> memory;
    size_t size;

    memoryStruct(size_t asize = 0) : memory(new uint8_t[asize]), size(asize) {}
    // or:
    // memoryStruct(size_t asize = 0) : memory(std::make_unique<uint8_t[]>(asize)), size(asize) {}
};

...

std::unique_ptr<memoryStruct> m_chunk(new memoryStruct(DesiredSize));
// or:
// std::unique_ptr<memoryStruct> m_chunk = std::make_unique<memoryStruct>(DesiredSize);

Which can then be simplified even further if you use std::vector instead of std::unique_ptr:

struct memoryStruct {
    std::vector<uint8_t> memory;
    memoryStruct(size_t size = 0) : memory(size) {}
};

...

std::unique_ptr<memoryStruct> m_chunk(new memoryStruct(DesiredSize));
// or:
// std::unique_ptr<memoryStruct> m_chunk = std::make_unique<memoryStruct>(DesiredSize);

Upvotes: 1

Related Questions