Accessing calloc'd data through a shared_ptr

2019-08-11 03:40发布

问题:

I'm trying to access the data that I previously allocated with the calloc method through a shared_ptr. For some reason I can't access it (keeps on crashing with EXC_BAD_ACCESS) on glTexImage2D (last line of my code snippets).

My util method to load the data:

shared_ptr<ImageData> IOSFileSystem::loadImageFile(string path) const
{
    // Result
    shared_ptr<ImageData> result = shared_ptr<ImageData>();

    ...

    // Check if file exists
    if([[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:NO])
    {
        ...

        GLubyte *spriteData = (GLubyte*) calloc(width * height * 4, sizeof(GLubyte));

        ...

        // Put result in shared ptr
        shared_ptr<GLubyte> spriteDataPtr = shared_ptr<GLubyte>(spriteData);
        result = shared_ptr<ImageData>(new ImageData(path, width, height, spriteDataPtr));
    }
    else
    {
        cout << "IOSFileSystem::loadImageFile -> File does not exist at path.\nPath: " + path;
        exit(1);
    }

    return result;
}

Header for ImageData:

class ImageData
{
public:
    ImageData(string path, int width, int height, shared_ptr<GLubyte> data);
    ~ImageData();

    string getPath() const;

    int getWidth() const;
    int getHeight() const;

    shared_ptr<GLubyte> getData() const;

private:
    string path;

    int width;
    int height;

    shared_ptr<GLubyte> data;
};

File that calls the util class:

void TextureMaterial::load()
{
    shared_ptr<IFileSystem> fileSystem = ServiceLocator::getFileSystem();
    shared_ptr<ImageData> imageData = fileSystem->loadImageFile(path);

    this->bind(imageData);
}



void TextureMaterial::bind(shared_ptr<ImageData> data)
{
    // Pointer to pixel data
    shared_ptr<GLubyte> pixelData = data->getData();

    ...

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data->getWidth(), data->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixelData);
}

Just for the record: if I throw out all shared_ptr's I'm able to access the data. Signature for glTexImage2D:

void glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *data);

Additional question: normally you have to free(spriteData) but since I gave the data to a shared_ptr, will the data be free'd when the shared_ptr is removed?

回答1:

I think this is your problem:

..., &pixelData);

You are taking an address of a local variable (of type shared_ptr<GLubyte>), which is silently cast to void*, instead of getting the pointer from it. Replace it with:

..., pixelData.get());


回答2:

shared_ptr cannot magically guess how to release the memory. By default it tries to delete it, and since you didn't use new, that ends up in disaster.

You need to tell it how to do it:

shared_ptr<GLubyte>(spriteData, &std::free);