我正在尝试移植
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;
}
}
发布评论
评论(2)
你所拥有的应该是安全的。 (堆栈分配的)ArrayRef 创建堆分配的 Array 来支持它们,然后共享这些 Array。
编辑:感谢您发布
计数
。花了一些功夫,但我想我明白发生了什么。解决方案:不要将
L_PATTERNS_
或L_AND_G_PATTERNS_
声明为const
。或者,const_cast
获取所需的operator[]
。例如理由:
在
AbstractReader
中,您声明:然后在其构造函数中尝试赋值:
由于
L_PATTERNS_
是const
,L_PATTERNS_[i]< /code> 从 ArrayRef 调用方法>
:这将返回
L_PATTERNS_[i]
中内容的全新副本。然后进行分配(临时分配),保持原来的不变。当您稍后返回访问L_PATTERNS_[
xxx]
时,您将看到原始的、未初始化的值(这是一个 NULL 引用/指针)。因此出现了段错误。有点令人惊讶的是 ArrayRef 甚至允许这种分配。当然,它违反了“最小惊喜原则”。人们会期望编译器会发出错误。为了确保编译器将来更有帮助,我们需要对
ArrayRef
的operator[] const
给出稍微不同的定义 (Array.h:121) ,例如:或者也许(有警告):
进行任何更改后,编译器都不允许进行赋值。例如,海湾合作委员会报告:
What you have should be safe. The (stack allocated)
ArrayRef
s create heap allocatedArray
s to back them, and then share thoseArray
s.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_
orL_AND_G_PATTERNS_
asconst
. Alternately,const_cast
to get the desiredoperator[]
. E.g.Rationale:
In
AbstractReader
, you declare:Then in its constructor, you attempt an assignment:
Since
L_PATTERNS_
isconst
,L_PATTERNS_[i]
invokes a method fromArrayRef<ArrayRef<int> >
: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 accessL_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 ofArrayRef
'soperator[] const
(Array.h:121), such as:or perhaps (with caveats):
After making either change, the compiler disallows allow the assignment. GCC, for example, reports:
原因可能有几个。例如,您没有在粘贴中包含“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.