Boost.MultiArray作为类的成员:调整大小并复制断言崩溃

时间:2016-10-15 00:30:16

标签: c++ arrays c++11 boost

为了显示问题,假设您有一个名为basic_ma的类,并且其成员是MultiArray( MA )。还假设在构造函数(或方法)中,您在临时 MA (此处称为tmp)中进行了一些计算,并且您希望将tmp的内容复制到ma(此行为是理想的,我希望同时tmpma)。

// A class with a MultiArray member
class basic_ma {
public:
  basic_ma() { }

  // initialize ma
  basic_ma(size_t x, size_t y) {
    // I would like to compute in tmp and then copy to member ma
    array2d tmp(boost::extents[x][y]);
    // dummy stuff, some serious calculation in real life
    for(size_t i=0; i<tmp.shape()[0]; ++i) {
      for(size_t j=0; j<tmp.shape()[1]; ++j) {
        tmp[i][j] = (i+1.0)*(j+1.0);
      }
    }
    ma.resize(boost::extents[tmp.shape()[0]][tmp.shape()[1]]);
    ma = tmp;
    // Alternative function to copy
    //copy_ma(tmp, ma);
    } 

  void show() {
    cout << endl << "> Show ma" << endl;
    for(size_t i = 0; i < ma.shape()[0]; ++i) {
      cout << "> ";
      for(size_t j = 0; j < ma.shape()[1]; ++j) {
        cout << ma[i][j] << '\t';
      }
      cout << endl;
    }
    cout << endl;
  }
private:
  array2d ma;// MultiArray member
};

现在考虑另一个成员是前一个类的类。

// Another class has several (possibly a vector of) basic_ma's
class group_ma {
public:
  group_ma() { }
  // constructs basic_ma's
  group_ma(size_t x, size_t y) {
    bma1 = basic_ma(x, y);
    bma1.show();
    bma2 = basic_ma(y, x);
    bma2.show();
  }
private:
  basic_ma bma1;
  basic_ma bma2;
};

当我使用带有两个参数的构造函数实例化group_ma时,会出现断言问题:

a.out: /usr/include/boost/multi_array/multi_array_ref.hpp:484: boost::multi_array_ref<T, NumDims>& boost::multi_array_ref<T, NumDims>::operator=(const ConstMultiArray&) [with ConstMultiArray = boost::multi_array<double, 2ul>; T = double; long unsigned int NumDims = 2ul]: Assertion `std::equal(other.shape(),other.shape()+this->num_dimensions(), this->shape())' failed.
Aborted (core dumped)

以下是main

int main(int argc, char **argv) {

  basic_ma bma(3,5);// OK compile and run
  bma.show();// OK compile and run

  group_ma gma1;// OK compile and run

  gma1 = group_ma(3, 3);// Compile but assertion error when running

  group_ma gma2(4, 2);// Compile but assertion error when running

  unique_ptr<group_ma> gma_ptr = unique_ptr<group_ma>(new group_ma(5, 6));
  // Compile but assertion error when running

  return 0;
}

使用gcc version 6.2.1编译:

g++ main.cpp -std=gnu++11 -pedantic -Wall

basic_ma工作正常,使用group_ma时会出现问题。 我还尝试了另一个函数来复制 MA ,结果相同:

// copy Boost.MultiArray source to dest
void copy_ma(const array2d source, array2d& dest) {
  vector<size_t> grid;
  const size_t* shape = source.shape();
  grid.assign(shape, shape+source.num_dimensions());
  dest.resize(grid);
  for(size_t i=0; i<source.shape()[0]; ++i) {
    for(size_t j=0; j<source.shape()[1]; ++j) {
      dest[i][j] = source[i][j];
    }
  }
}

我看不出我做错了什么。 使用-DNDEBUG标志会引发内存错误:malloc(): memory corruption (fast)

整个代码在这里:

#include <iostream>
#include <boost/multi_array.hpp>
#include <memory>

using namespace std;

typedef boost::multi_array<double, 2> array2d;

// A class with a MultiArray member
class basic_ma {
public:
  basic_ma() { }
  // initialize ma
  basic_ma(size_t x, size_t y) {
    // I would like to compute in tmp and the copy to member ma
    array2d tmp(boost::extents[x][y]);
    // dummy stuff
    for(size_t i=0; i<tmp.shape()[0]; ++i) {
      for(size_t j=0; j<tmp.shape()[1]; ++j) {
        tmp[i][j] = (i+1.0)*(j+1.0);
      }
    }
    ma.resize(boost::extents[tmp.shape()[0]][tmp.shape()[1]]);
    ma = tmp;
    // Alternative function to copy
//     copy_ma(tmp, ma);
  }
  void show() {
    cout << endl << "> Show ma" << endl;
    for(size_t i = 0; i < ma.shape()[0]; ++i) {
        cout << "> ";
        for(size_t j = 0; j < ma.shape()[1]; ++j) {
          cout << ma[i][j] << '\t';
        }
        cout << endl;
    }
    cout << endl;
  }
private:
  array2d ma;// MultiArray member
};


// copy Boost.MultiArray source to dest
void copy_ma(const array2d source, array2d& dest) {
  vector<size_t> grid;
  const size_t* shape = source.shape();
  grid.assign(shape, shape+source.num_dimensions());
  dest.resize(grid);
  for(size_t i=0; i<source.shape()[0]; ++i) {
    for(size_t j=0; j<source.shape()[1]; ++j) {
      dest[i][j] = source[i][j];
    }
  }
}

// Another class will have several (possibly a vector of) basic_ma's
class group_ma {
public:
  group_ma() { }
  // constructs basic_ma's
  group_ma(size_t x, size_t y) {
    bma1 = basic_ma(x, y);
    bma1.show();
    bma2 = basic_ma(y, x);
    bma2.show();
  }
private:
  basic_ma bma1;
  basic_ma bma2;
};

int main(int argc, char **argv) {

  basic_ma bma(3,5);// OK compile and run
  bma.show();// OK compile and run

  group_ma gma1;// OK compile and run

  gma1 = group_ma(3, 3);// Compile but assertion error when running

  group_ma gma2(4, 2);// Compile but assertion error when running

  unique_ptr<group_ma> gma_ptr = unique_ptr<group_ma>(new group_ma(5, 6));
  // Compile but assertion error when running

  return 0;
}

1 个答案:

答案 0 :(得分:0)

错误消息表明在分配期间阵列的大小不同。有几种方法可以解决它。在group_ma中使用构造函数:

group_ma(size_t x, size_t y)
    :bma1( x, y )
    ,bma2( y, x )
{
    //bma1 = basic_ma(x, y);
    bma1.show();
    //bma2 = basic_ma(y, x);
    bma2.show();
}

默认构造函数没有给你一个3x3。 Boost docs谈论调整multi_array的大小,如果你必须分配,你可以这样做。但需要注意的是,尺寸保持不变。

将会员添加到basic_ma

void resize(size_t x, size_t y )
{
    ma.resize( boost::extents[x][y] );
}

然后:

basic_ma not_initialized;
not_initialized.resize( 3, 3 );
basic_ma bma(3,3);
bma.show();
not_initialized= bma; // now this works
not_initialized.show( );

另一个想法,你可以在自己的赋值运算符中调整大小......

因此,如果您希望basic_ma保持私密状态。让group_ma成为basic_ma的朋友。然后,您可以将其添加到group_ma

void operator = ( group_ma& source )
{
    bma1.resize( source.bma1.ma.shape( )[ 0 ], source.bma1.ma.shape( )[ 1 ] );
    bma2.resize( source.bma2.ma.shape( )[ 0 ], source.bma2.ma.shape( )[ 1 ] );
    bma1= source.bma1;
    bma2= source.bma2;
}

然后这个有效:

group_ma gma1;
gma1 = group_ma(3, 3);
group_ma gma2(4, 2);
gma1= gma2;

可能有更好的方法,我不知道,因为我看不到。但我认为这可能适合你。

还有另一个想法,如果你有不同类型的群体会更好。在basic_ma的赋值运算符中调整大小。然后在小组作业中你只需要:

void operator = ( group_ma& source )
{
    bma1= source.bma1;
    bma2= source.bma2;
}