如何在 C++ 中创建二维数组使用这个特定的容器

发布于 2024-08-03 13:34:57 字数 1958 浏览 4 评论 0 原文

我正在尝试移植
int a[][]
从Java到C++。我使用此类作为整数的容器 ArrayRef 因为它处理引用,并且该项目使用它广泛地。在 AbstractReader 类中我声明了

const ArrayRef; START_END_PATTERN_;
const ArrayRef; MIDDLE_PATTERN_;
const ArrayRef; > L_PATTERNS_;
const ArrayRef; > L_AND_G_PATTERNS_;

<代码> 静态 int START_END_PATTERN[];
static int MIDDLE_PATTERN[];
static int L_PATTERNS[10][4];
static int L_AND_G_PATTERNS[20][4];
请注意尾随下划线以区分两个变量。

我不知道如何初始化二维 ArrayRef。我在这里发布的内容将会出现段错误,因为这些 ArrayRef 是在堆栈上分配的。有人有一个聪明的方法来做到这一点吗?

我实际上设法让它工作的唯一方法是使用 ArrayRef< Ref; > > 通过使 ArrayRef 继承自 Counted,Counted 基本上是一个允许在 C++ 中进行引用计数的类。但为了访问元素,我必须执行类似 *(foo[i])[j] 的操作,这比 foo[i][j] 稍微麻烦一些。

int AbstractReader::L\_AND\_G_PATTERNS[20][4] = {

 {3, 2, 1, 1}, // 0
 {2, 2, 2, 1}, // 1
 {2, 1, 2, 2}, // 2
 {1, 4, 1, 1}, // 3
 {1, 1, 3, 2}, // 4
 {1, 2, 3, 1}, // 5
 {1, 1, 1, 4}, // 6
 {1, 3, 1, 2}, // 7
 {1, 2, 1, 3}, // 8
 {3, 1, 1, 2},  // 9
 // G patterns

 {1, 1, 2, 3}, // 0
 {1, 2, 2, 2}, // 1
 {2, 2, 1, 2}, // 2
 {1, 1, 4, 1}, // 3
 {2, 3, 1, 1}, // 4
 {1, 3, 2, 1}, // 5
 {4, 1, 1, 1}, // 6
 {2, 1, 3, 1}, // 7
 {3, 1, 2, 1}, // 8
 {2, 1, 1, 3}  // 9
 };

 AbstractReader::AbstractReader() 
 : decodeRowStringBuffer_(ostringstream::app),
 START_END_PATTERN_(START_END_PATTERN, 3),
 MIDDLE_PATTERN_(MIDDLE_PATTERN, 5),
 L_PATTERNS_(10),
 L_AND_G_PATTERNS_(20) {

  for (int i = 0; i < 20; i++) {
   if (i < 10) {
    L_PATTERNS_[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
   }
   ArrayRef<int> lgpattern((L_AND_G_PATTERNS[i]), 4);
   L_AND_G_PATTERNS_[i] = lgpattern;
  }
 }

I'm trying to port a
int a[][]
from Java to C++. I'm using this class as a container ArrayRef for ints because it handles references, and the project uses it extensively. In the AbstractReader class I declared


const ArrayRef<int> START_END_PATTERN_;
const ArrayRef<int> MIDDLE_PATTERN_;
const ArrayRef<ArrayRef<int> > L_PATTERNS_;
const ArrayRef<ArrayRef<int> > L_AND_G_PATTERNS_;

and


static int START_END_PATTERN[];
static int MIDDLE_PATTERN[];
static int L_PATTERNS[10][4];
static int L_AND_G_PATTERNS[20][4];

Note the trailing underscore to differentiate the two variables.

I'm not sure what to do in order to initialize the two-dimensional ArrayRef. What I'm posting here will segfault because those ArrayRefs are being allocated on the stack. Anybody have a clever way to do this?

The only way I've actually managed to get it to work is using a ArrayRef< Ref<ArrayRef<int> > > by making ArrayRef inherit from Counted, which is basically a class that allows for Reference Counting in C++. But in order to access the elements I hen have to do something like *(foo[i])[j], which is slightly nastier than foo[i][j].

int AbstractReader::L\_AND\_G_PATTERNS[20][4] = {

 {3, 2, 1, 1}, // 0
 {2, 2, 2, 1}, // 1
 {2, 1, 2, 2}, // 2
 {1, 4, 1, 1}, // 3
 {1, 1, 3, 2}, // 4
 {1, 2, 3, 1}, // 5
 {1, 1, 1, 4}, // 6
 {1, 3, 1, 2}, // 7
 {1, 2, 1, 3}, // 8
 {3, 1, 1, 2},  // 9
 // G patterns

 {1, 1, 2, 3}, // 0
 {1, 2, 2, 2}, // 1
 {2, 2, 1, 2}, // 2
 {1, 1, 4, 1}, // 3
 {2, 3, 1, 1}, // 4
 {1, 3, 2, 1}, // 5
 {4, 1, 1, 1}, // 6
 {2, 1, 3, 1}, // 7
 {3, 1, 2, 1}, // 8
 {2, 1, 1, 3}  // 9
 };

 AbstractReader::AbstractReader() 
 : decodeRowStringBuffer_(ostringstream::app),
 START_END_PATTERN_(START_END_PATTERN, 3),
 MIDDLE_PATTERN_(MIDDLE_PATTERN, 5),
 L_PATTERNS_(10),
 L_AND_G_PATTERNS_(20) {

  for (int i = 0; i < 20; i++) {
   if (i < 10) {
    L_PATTERNS_[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
   }
   ArrayRef<int> lgpattern((L_AND_G_PATTERNS[i]), 4);
   L_AND_G_PATTERNS_[i] = lgpattern;
  }
 }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

难忘№最初的完美 2024-08-10 13:34:57

你所拥有的应该是安全的。 (堆栈分配的)ArrayRef 创建堆分配的 Array 来支持它们,然后共享这些 Array。

编辑:感谢您发布计数。花了一些功夫,但我想我明白发生了什么。

解决方案:不要将 L_PATTERNS_L_AND_G_PATTERNS_ 声明为 const。或者,const_cast 获取所需的operator[]。例如

const_cast<ArrayRef<ArrayRef<int> > &>(L_PATTERNS_)[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);

理由
AbstractReader 中,您声明:

const ArrayRef<ArrayRef<int> > L_PATTERNS_;

然后在其构造函数中尝试赋值:

AbstractReader::AbstractReader() :
{
    ...
    L_PATTERNS_[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
    ...
}

由于 L_PATTERNS_constL_PATTERNS_[i]< /code> 从 ArrayRef 调用方法>

T operator[](size_t i) const { return (*array_)[i]; }

这将返回 L_PATTERNS_[i] 中内容的全新副本。然后进行分配(临时分配),保持原来的不变。当您稍后返回访问 L_PATTERNS_[xxx] 时,您将看到原始的、未初始化的值(这是一个 NULL 引用/指针)。因此出现了段错误。

有点令人惊讶的是 ArrayRef 甚至允许这种分配。当然,它违反了“最小惊喜原则”。人们会期望编译器会发出错误。为了确保编译器将来更有帮助,我们需要对 ArrayRefoperator[] const 给出稍微不同的定义 (Array.h:121) ,例如:

const T operator[](size_t i) const { return (*array_)[i]; }

或者也许(有警告):

const T& operator[](size_t i) const { return (*array_)[i]; }

进行任何更改后,编译器都不允许进行赋值。例如,海湾合作委员会报告:

error: passing 'const common::ArrayRef<int>' as 'this' argument of 'common::ArrayRef<T>& common::ArrayRef<T>::operator=(const common::ArrayRef<T>&) [with T = int]' discards qualifiers

What you have should be safe. The (stack allocated) ArrayRefs create heap allocated Arrays to back them, and then share those Arrays.

Edit: Thanks for posting Counted. Took a bit of work, but I think I see what's going on.

Solution: Don't declare L_PATTERNS_ or L_AND_G_PATTERNS_ as const. Alternately, const_cast to get the desired operator[]. E.g.

const_cast<ArrayRef<ArrayRef<int> > &>(L_PATTERNS_)[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);

Rationale:
In AbstractReader, you declare:

const ArrayRef<ArrayRef<int> > L_PATTERNS_;

Then in its constructor, you attempt an assignment:

AbstractReader::AbstractReader() :
{
    ...
    L_PATTERNS_[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
    ...
}

Since L_PATTERNS_ is const, L_PATTERNS_[i] invokes a method from ArrayRef<ArrayRef<int> >:

T operator[](size_t i) const { return (*array_)[i]; }

This returns a brand new copy of what was at L_PATTERNS_[i]. The assignment then occurs (into a temporary), leaving the original unchanged. When you later go back to access L_PATTERNS_[xxx], you're looking at the original, uninitialized value (which is a NULL reference/pointer). Thus the segfault.

Somewhat surprising is that ArrayRef even allows this assignment. Certainly it breaks the "Principle of Least Surprise". One would expect the compiler to issue an error. To make sure that the compiler is more helpful in the future, we need to give a slightly different definition of ArrayRef's operator[] const (Array.h:121), such as:

const T operator[](size_t i) const { return (*array_)[i]; }

or perhaps (with caveats):

const T& operator[](size_t i) const { return (*array_)[i]; }

After making either change, the compiler disallows allow the assignment. GCC, for example, reports:

error: passing 'const common::ArrayRef<int>' as 'this' argument of 'common::ArrayRef<T>& common::ArrayRef<T>::operator=(const common::ArrayRef<T>&) [with T = int]' discards qualifiers
本王不退位尔等都是臣 2024-08-10 13:34:57

原因可能有几个。例如,您没有在粘贴中包含“Counted”类,并且在某个时刻,a->retain() 被调用(第 130 行)。该方法未显示。

Causes may be several. For instance, you don't include in your paste the "Counted" class, and at some point, a->retain() is called (line 130). This method is not shown.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文