0

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;
  }
 }
4

2 に答える 2

1

あなたが持っているものは安全でなければなりません。(割り当てられたスタック)は、それらをバックアップするためにArrayRef割り当てられたヒープを作成Arrayし、それらを共有しArrayます。

編集:投稿していただきありがとうございCountedます。少し手間がかかりましたが、何が起こっているのかがわかると思います。

解決策L_PATTERNS_: orL_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_isconstであるため、L_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 に答える