0

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

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_;

static 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<int> > >ArrayRef 从 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;
  }
 }
4

2 回答 2

1

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

编辑:感谢张贴Counted。做了一些工作,但我想我明白发生了什么。

解决方案:不要声明L_PATTERNS_or L_AND_G_PATTERNS_as 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_is constL_PATTERNS_[i]从 调用方法ArrayRef<ArrayRef<int> >

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

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

有点令人惊讶的是,ArrayRef竟然允许这个赋值。当然它打破了“最小惊喜原则”。人们会期望编译器发出错误。为确保编译器在未来更有帮助,我们需要对ArrayRef's operator[] const(Array.h:121) 给出一个稍微不同的定义,例如:

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

或者也许(有警告):

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

在进行任一更改后,编译器不允许赋值。例如,GCC 报告:

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
于 2009-09-02T12:59:33.053 回答
0

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

于 2009-09-02T15:14:20.780 回答