gpt4 book ai didi

libpng 的 C++ 抽象导致 malloc 中的崩溃——删除 "Jagged"二维数组时

转载 作者:行者123 更新时间:2023-11-28 08:07:33 25 4
gpt4 key购买 nike

这个crash对应的类是:

#ifndef IMAGE_DATA_
#define IMAGE_DATA_

#include <stdexcept>

template <typename data_type>
class ImageData
{
public:
ImageData(unsigned long width, unsigned long height);
~ImageData();
data_type **&get_data();
unsigned long int get_width() const
{
return _m_Width;
}
unsigned long int get_height() const
{
return _m_Height;
}
protected:
ImageData(ImageData &copy);
ImageData& operator= (ImageData &copy);
private:
data_type **_m_rData;
unsigned long _m_Width;
unsigned long _m_Height;
};

template <typename data_type>
ImageData<data_type>::ImageData(unsigned long width, unsigned long height) :
_m_rData(NULL),
_m_Width(width),
_m_Height(height)
{
if (width == 0 || height == 0)
throw std::runtime_error("Invalid width or height");

try {
_m_rData = new data_type*[_m_Height]();
for (unsigned long int i = 0; i < _m_Height; ++i) {
_m_rData[i] = NULL;
}
for (unsigned long int i = 0; i < _m_Height; ++i) {
_m_rData[i] = new data_type[_m_Width];
}
}
catch (std::bad_alloc e) {
throw std::runtime_error("Failure to create space for Image");
}
}

template <typename data_type>
ImageData<data_type>::~ImageData()
{
for (unsigned long i = 0; i < _m_Height; ++i) {
delete [] _m_rData[i];
_m_rData[i] = NULL;
}
delete [] _m_rData;
_m_rData = NULL;
}

template <typename data_type>
data_type **&ImageData<data_type>::get_data()
{
return _m_rData;
}

#endif

它的使用方式如下:

PNGFileReader::PNGFileReader(const std::string &path) :
_m_Image(NULL),
_m_pPNG(NULL),
_m_pPNGInfo(NULL)
{
...
/*
* Read Image in all at once into users data
*/
_m_Image = new ImageData<unsigned char>(width, height);
png_read_image(_m_pPNG, _m_Image->get_data());
png_read_end(_m_pPNG, NULL);
fclose(_m_CFilePointer);
_m_CFilePointer = NULL;
}

PNGFileReader::~PNGFileReader()
{
if (_m_CFilePointer) {
fclose(_m_CFilePointer);
}
png_destroy_read_struct(&_m_pPNG, &_m_pPNGInfo, NULL);
delete _m_Image;
}

当使用调试器逐步执行时,ImageData 类中的 _m_rData 与我在其上使用 new 时的指针相同。我什至尝试使用 if == NULL 语句将 delete 语句包装在 ImageData 析构函数中。但是,在运行我的代码时,我仍然得到一个 sigabrt。来自 gdb 的堆栈跟踪是:

0   __GI_raise  raise.c 64  0x3512a36285    
1 __GI_abort abort.c 91 0x3512a37b9b
2 __libc_message libc_fatal.c 198 0x3512a77a7e
3 malloc_printerr malloc.c 5021 0x3512a7dda6
4 _int_free malloc.c 3942 0x3512a7f08e
5 ImageData<unsigned char>::~ImageData imagedata.h 57 0x40236d
6 PNGFileReader::~PNGFileReader pngfilereader.cpp 59 0x401ed3
7 main main.cpp 8 0x40246a

更新

对于任何好奇的人,以下内容现在都可以使用。显然这是 png_alligns 其数据的方式问题。我想这迫使你使用 libpng 的方法调用,它在内部使用 free 和 malloc,而不是新的。这本质上与调用 free(data) 相同,其中数据是使用 data = new type[N] 创建的。下面的代码描述了如何正确使用 libpng。

#ifndef PNG_FILE_READER_H_
#define PNG_FILE_READER_H_

#include "imagedata.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
#include <iostream>
#include <vector>
#include <string>

template <typename data_type>
class ImageData;

class PNGFileReader
{
public:
// Ctor and Dtor
PNGFileReader(const std::string &path);
~PNGFileReader();

// For testing purposes
friend std::ostream &operator<< (std::ostream &out,
PNGFileReader *object)
{
for (unsigned long i = 0; i < object->get_image_height(); ++i) {
for (unsigned long j = 0; j < object->get_image_width(); ++j) {
png_byte c = object->_m_ImageData[i][j];
out << c;
}
}
return out;
}

// Getters
long unsigned int get_image_width() const;
long unsigned int get_image_height() const;

private:
// Helper functions:
bool _create_png_structs();

// Member variables:
FILE *_m_CFilePointer;
unsigned long int _m_ImageWidth;
unsigned long int _m_ImageHeight;
png_bytepp _m_ImageData;
png_structp _m_pPNG;
png_infop _m_pPNGInfo;

// Enums
enum PNGBOOL {NOT_PNG, PNG};
enum PNGERRORS {ERROR, SUCCESS};
};

#endif /* PNG_FILE_READER_H_ */

#include "pngfilereader.h"
#include "filereader.h"
#include <stdexcept>


PNGFileReader::PNGFileReader(const std::string &path) :
_m_ImageData(NULL),
_m_pPNG(NULL),
_m_pPNGInfo(NULL)
{
/*
* Check if first 8 bytes are the correct PNG header
*/
enum {BYTES_TO_READ = 8};
unsigned char sig[BYTES_TO_READ];
FileReader(path, sig, BYTES_TO_READ);
bool not_png = png_sig_cmp(sig, 0, BYTES_TO_READ);
if (not_png) {
throw std::runtime_error("Your file is not of PNG format");
}

/*
* Create the png structs using a FILE *. libpng requires
* this type and will not take a C++ stream
*/
_m_CFilePointer = fopen(path.c_str(), "rb");
if (!_m_CFilePointer) {
throw std::runtime_error("Failure to open PNG file");
}
if (!_create_png_structs()) {
throw std::runtime_error("Failure to create PNG structs");
}

/*
* Initialize PNG io and read data into PNG structs
*/
png_init_io(_m_pPNG, _m_CFilePointer);
png_read_info(_m_pPNG, _m_pPNGInfo);
_m_ImageHeight = png_get_image_height(_m_pPNG, _m_pPNGInfo);
_m_ImageWidth = png_get_rowbytes(_m_pPNG, _m_pPNGInfo);

/*
* Create sufficient PNG Space and Read Image in all at
* once into users data. Note that you have to use png's
* types to prevent sigabrt (6) while freeing memory.
*/
_m_ImageData = (png_bytepp)png_malloc(_m_pPNG,
sizeof(png_bytep)*_m_ImageHeight);
if (_m_ImageData == NULL) {
throw std::runtime_error("Memory allocation failure");
}
for (unsigned long int i = 0; i < _m_ImageHeight; ++i) {
_m_ImageData[i] = NULL;
}
for (unsigned long int i = 0; i < _m_ImageHeight; ++i) {
_m_ImageData[i] = (png_bytep)png_malloc(_m_pPNG,
sizeof(png_byte)*_m_ImageWidth);
if (_m_ImageData[i] == NULL) {
throw std::runtime_error("Memory allocation failure.");
}
}
png_read_image(_m_pPNG, _m_ImageData);
png_read_end(_m_pPNG, NULL);
fclose(_m_CFilePointer);
_m_CFilePointer = NULL;
}

PNGFileReader::~PNGFileReader()
{
if (_m_CFilePointer) {
fclose(_m_CFilePointer);
}
/*
* Free all resources (-1)
*/
png_free_data(_m_pPNG, _m_pPNGInfo, PNG_FREE_ALL, -1);
for (unsigned long int i = 0; i < _m_ImageHeight; ++i) {
png_free(_m_pPNG, _m_ImageData[i]);
}
free(_m_ImageData);
png_destroy_read_struct(&_m_pPNG, &_m_pPNGInfo, NULL);
}
// Getters
long unsigned int PNGFileReader::get_image_width() const
{
return _m_ImageWidth;
}

long unsigned int PNGFileReader::get_image_height() const
{
return _m_ImageHeight;
}

// Private helper functions
bool PNGFileReader::_create_png_structs()
{
/*
* Create the pointer to main libpng struct, as well as
* two info structs to maintain information after, and
* prior to all operations on png m_Data. Only necessary
* to release resource after function succeeds.
*/
_m_pPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
NULL, NULL);
if (!_m_pPNG){
return PNGFileReader::ERROR;
}

_m_pPNGInfo = png_create_info_struct(_m_pPNG);
if (!_m_pPNGInfo) {
return PNGFileReader::ERROR;
}

return PNGFileReader::SUCCESS;
}

最佳答案

如果你需要一个真正的二维数组来传递给一个库,但又想拥有锯齿状数组的灵 active ,你要做的是

  1. 像往常一样分配第一级指针 block
  2. 不是分配 mn 单元格(第一级 block 中的每个指针一个),而是分配一组 n*m 单元格,然后将第一级指针设置为指向每个 n 位置。通过这种方式,主要分配的大小和在内存中的布局就像二维数组一样,但您仍然可以使用双指针取消引用 [][] 语法来访问单元格。
  3. 将二级分配的开始传递给图书馆。

之所以可行,是因为对谁在内存中布置多维数组有严格的要求(即,在每个解释级别上必须是连续的)。

关于libpng 的 C++ 抽象导致 malloc 中的崩溃——删除 "Jagged"二维数组时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9957853/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com