在下面的代码中是创建2D数组时所需的初始第一个循环,或者如果存储器分配失败,指向实际行的指针是否会初始化为NULL?
unsigned char **row_pointers;
try
{
row_pointers = new unsigned char *[height];
for (int i = 0; i < height; ++i)
row_pointers[i] = NULL;
for (int i = 0; i < height; ++i)
row_pointers[i] = new unsigned char[width];
}
catch (std::bad_alloc)
{
throw std::runtime_error("Failure to allocate memory for raw data");
}
更新
为了澄清,我正在看的代码是:
149 /*
150 * Allocate sufficient space for the data
151 */
152 unsigned char **row_pointers;
153 try
154 {
155 row_pointers = new unsigned char *[height]();
156 for (int i = 0; i < height; ++i)
157 row_pointers[i] = new unsigned char[width];
158 }
159 catch (std::bad_alloc)
160 {
161 /*
162 * If insufficient memory than try and clean up
163 * and throw runtime error
164 */
165 for (int i = 0; i < height; ++i)
166 {
167 if (row_pointers[i] != NULL)
168 {
169 delete row_pointers[i];
170 }
171 }
172 throw std::runtime_error("Failure to allocate raw memory for data");
173 }
... // White Space
177
178 /*
179 * Now read the data all at once (no need to handle interlacing
180 */
181 png_read_image(m_pPNG, row_pointers);
182
183 for (int i = 0; i < height; ++i)
184 {
185 for (int j = 0; j < width; ++j)
186 std::cout << row_pointers[i][j];
187 std::cout << std::endl;
188 }
答案 0 :(得分:3)
此操作未初始化分配有new unsigned char*[height]
的数组。如果任何分配失败,它将抛出异常。在您的代码中,您接下来初始化您的数组。我认为这应该是这样的:
std::fill_n(row_pointers, height, 0);
当然,如果任何后续分配失败,这个数组将会泄露,到目前为止所分配的所有其他数组都将泄露。你可以在catch
- 块中清理这个混乱。
就个人而言,我无法应对多次清理:只是太复杂而无法做到正确。就个人而言,我会使用两个std::vector<T>
代替,捆绑到一个类中:
std::vector<unsigned char*>
被初始化为指向子向量的开头std::vector<unsigned char>
来容纳所有子向量一旦分配了这些指针,第一个向量中的指针就会被设置为指向适当位置的第二个向量。方便的是,如果出现任何问题,两个向量的析构函数将负责清理。
这是这样的:
#include <vector>
#include <cstddef>
struct array2d
{
array2d(std::size_t height, std::size_t width)
: inner_(height * width)
, outer_(height)
{
for (std::size_t i(0); i != height; ++i) {
this->outer_[i] = &this->inner_[i * width];
}
}
unsigned char** get() { return &this->outer_[0]; }
std::vector<unsigned char> inner_;
std::vector<unsigned char*> outer_;
};
当你得到这种类型的对象picture
时,你可以使用picture.get()
来获得适合传递给C函数的指针。
答案 1 :(得分:1)
这取决于编译器和选项,但为了安全起见,您应该保留初始化,如果您期望它。
某些带有debug选项的编译器将使用0值初始化row_pointers
数组。其他人会用标记填充它(如0xcc
),而其他人则会将其保留为未初始化状态。
我不确定,但我认为可能还有一些选项会返回NULL而不是抛出std::bad_alloc
,在这种情况下,额外的初始化将是不必要的。
然而,如果有疑问,请明确!
答案 2 :(得分:0)
这对你来说可能是一个很好的解读:
答案 3 :(得分:-2)
您要编译哪个操作系统?对于某些(例如linux),new将永远不会失败,相反,当您使用内存时,您将在稍后获得段违规!
在这种情况下,您将在第一次初始化循环期间触发段违规。
这可能是阅读一些Herb Sutters GOTW
的好时机请参阅:GOTW - To New, Perchance To Throw, Part 2
注意:在新增任一维度后,您可以使用memset
初始化数据,因此第一个循环可以由memset( row_pointers, sizeof(unsigned char *)*height, 0 )
替换。