在 cpp 中对象初始化后设置数组的边界
Set the bounds of an array after object initialisation in cpp
我正在使用 C++ 编写图像渲染器,这是我从头开始编写的(我不想使用标准库以外的任何东西),但在尝试存储图像时遇到了一些麻烦。我用来存储图像的 class 看起来像这样:
class RawImage
{
private:
RGB pixels[][][3] = {};
public:
int width = 0;
int height = 0;
RawImage(int width, int height)
{
this->width = width;
this->height = height;
};
RGB GetPixel(int x, int y)
{
if (x < 0 || x > width - 1)
return RGB(0.f, 0.f, 0.f);
if (y < 0 || y > height - 1)
return RGB(0.f, 0.f, 0.f);
return pixels[x][y];
};
int SetPixel(int x, int y, RGB color)
{
if (x < 0 || x > width - 1)
return -1;
if (y < 0 || y > height - 1)
return -1;
this->pixels[x][y] = color;
return 0;
}
};
当我尝试编译这段代码时,g++ 编译器给出了以下错误:
declaration of ‘pixels’ as multidimensional array must have bounds for
all dimensions except the first.
如何使用第一个维度大小不同但第三个维度大小固定的多维数组?
Set the bounds of an array after object initialisation in cpp
数组的大小在其生命周期内永远不会改变。它是在创建时设置的。从技术上讲,这对您来说不是问题,因为您可以在构造函数中初始化数组。
但是,数组变量的大小必须是编译时常量,因此您不能接受该大小作为构造函数参数。
您可以使用动态数组。最方便的方法是使用 std::vector
.
数组在 C++ 语言中并不是真正的一等公民,multi-dimensional 数组根本不是。没有办法声明一个 multi-dimensional 数组,其中超过第一维的不是编译时常量,句号。基本原理是普通数组是低级对象,只能用于更高级别的容器。不幸的是,由于迭代器的工作方式,构建真正的 multi-level 容器来包装其维度仅在编译时已知的多维数组绝非易事。如果您可以接受,一种简单的方法是使用 operator ()
作为访问器方法:pixels(x, y)
而不是 pixels[x][y]
在知道动态维度的容器中。
假设(正如您在评论中确认的那样)您的 RGB
类型是一个 class 或具有三个组件的结构,其构造函数与您的 GetPixel
中使用的形式相同函数,那么你实际上想要一个 2D 数组。但是(正如评论中也提到的那样),通常将位图存储为扁平的 one-dimensional 大小 width × height
的数组更有效。然后可以使用公式 array[y * width + x]
对该数组中的适当元素进行索引(假设 row-major 顺序和 y-ordinates 增加 down 位图)。
你仍然有编译时未知维度的问题,所以你不能使用普通数组。但是 std::vector
container 非常适合这个:只需在 RawImage
构造函数中调整它的大小,然后它就可以像普通数组一样使用。另外,当RawImage
class的对象被销毁时,所使用的内存会自动释放。
这是您的 class 的可能实现,使用这样的 std::vector
:
#include <vector>
class RawImage {
private:
std::vector<RGB> pixels;
public:
int width = 0;
int height = 0;
RawImage(int width, int height)
{
this->width = width;
this->height = height;
pixels.resize(width * height);
};
RGB GetPixel(int x, int y)
{
if (x < 0 || x >= width )
return RGB(0.f, 0.f, 0.f);
if (y < 0 || y >= height)
return RGB(0.f, 0.f, 0.f);
return pixels[y * width + x];
};
int SetPixel(int x, int y, RGB color)
{
if (x < 0 || x >= width)
return -1;
if (y < 0 || y >= height)
return -1;
pixels[y * width + x] = color;
return 0;
}
};
重要提示:为了像这样使用std::vector<RGB>
容器,RGB
class/structure必须有默认构造函数。我不知道你是如何实现 class 的,但像下面这样的东西会起作用:
struct RGB {
float r, g, b;
RGB(float fr, float fg, float fb) : r{ fr }, g{ fg }, b{ fb } { }
RGB() : r{ 0 }, g{ 0 }, b{ 0 } { } // Default c'tor required by std::vector
};
或者,为简洁起见,您可以 'merge' 通过为每个参数提供默认值,将您的默认构造函数转换为采用三个 float
参数的构造函数:
struct RGB {
float r, g, b;
RGB(float fr = 0, float fg = 0, float fb = 0) : r{ fr }, g{ fg }, b{ fb } { }
};
我正在使用 C++ 编写图像渲染器,这是我从头开始编写的(我不想使用标准库以外的任何东西),但在尝试存储图像时遇到了一些麻烦。我用来存储图像的 class 看起来像这样:
class RawImage
{
private:
RGB pixels[][][3] = {};
public:
int width = 0;
int height = 0;
RawImage(int width, int height)
{
this->width = width;
this->height = height;
};
RGB GetPixel(int x, int y)
{
if (x < 0 || x > width - 1)
return RGB(0.f, 0.f, 0.f);
if (y < 0 || y > height - 1)
return RGB(0.f, 0.f, 0.f);
return pixels[x][y];
};
int SetPixel(int x, int y, RGB color)
{
if (x < 0 || x > width - 1)
return -1;
if (y < 0 || y > height - 1)
return -1;
this->pixels[x][y] = color;
return 0;
}
};
当我尝试编译这段代码时,g++ 编译器给出了以下错误:
declaration of ‘pixels’ as multidimensional array must have bounds for all dimensions except the first.
如何使用第一个维度大小不同但第三个维度大小固定的多维数组?
Set the bounds of an array after object initialisation in cpp
数组的大小在其生命周期内永远不会改变。它是在创建时设置的。从技术上讲,这对您来说不是问题,因为您可以在构造函数中初始化数组。
但是,数组变量的大小必须是编译时常量,因此您不能接受该大小作为构造函数参数。
您可以使用动态数组。最方便的方法是使用 std::vector
.
数组在 C++ 语言中并不是真正的一等公民,multi-dimensional 数组根本不是。没有办法声明一个 multi-dimensional 数组,其中超过第一维的不是编译时常量,句号。基本原理是普通数组是低级对象,只能用于更高级别的容器。不幸的是,由于迭代器的工作方式,构建真正的 multi-level 容器来包装其维度仅在编译时已知的多维数组绝非易事。如果您可以接受,一种简单的方法是使用 operator ()
作为访问器方法:pixels(x, y)
而不是 pixels[x][y]
在知道动态维度的容器中。
假设(正如您在评论中确认的那样)您的 RGB
类型是一个 class 或具有三个组件的结构,其构造函数与您的 GetPixel
中使用的形式相同函数,那么你实际上想要一个 2D 数组。但是(正如评论中也提到的那样),通常将位图存储为扁平的 one-dimensional 大小 width × height
的数组更有效。然后可以使用公式 array[y * width + x]
对该数组中的适当元素进行索引(假设 row-major 顺序和 y-ordinates 增加 down 位图)。
你仍然有编译时未知维度的问题,所以你不能使用普通数组。但是 std::vector
container 非常适合这个:只需在 RawImage
构造函数中调整它的大小,然后它就可以像普通数组一样使用。另外,当RawImage
class的对象被销毁时,所使用的内存会自动释放。
这是您的 class 的可能实现,使用这样的 std::vector
:
#include <vector>
class RawImage {
private:
std::vector<RGB> pixels;
public:
int width = 0;
int height = 0;
RawImage(int width, int height)
{
this->width = width;
this->height = height;
pixels.resize(width * height);
};
RGB GetPixel(int x, int y)
{
if (x < 0 || x >= width )
return RGB(0.f, 0.f, 0.f);
if (y < 0 || y >= height)
return RGB(0.f, 0.f, 0.f);
return pixels[y * width + x];
};
int SetPixel(int x, int y, RGB color)
{
if (x < 0 || x >= width)
return -1;
if (y < 0 || y >= height)
return -1;
pixels[y * width + x] = color;
return 0;
}
};
重要提示:为了像这样使用std::vector<RGB>
容器,RGB
class/structure必须有默认构造函数。我不知道你是如何实现 class 的,但像下面这样的东西会起作用:
struct RGB {
float r, g, b;
RGB(float fr, float fg, float fb) : r{ fr }, g{ fg }, b{ fb } { }
RGB() : r{ 0 }, g{ 0 }, b{ 0 } { } // Default c'tor required by std::vector
};
或者,为简洁起见,您可以 'merge' 通过为每个参数提供默认值,将您的默认构造函数转换为采用三个 float
参数的构造函数:
struct RGB {
float r, g, b;
RGB(float fr = 0, float fg = 0, float fb = 0) : r{ fr }, g{ fg }, b{ fb } { }
};