提振.MultiArray作为类的成员:调整大小和复制断言崩溃

Boost.MultiArray as a member of a class: resize and copy assertion crash

本文关键字:复制 崩溃 断言 调整 MultiArray 成员 提振      更新时间:2023-10-16

为了说明这个问题,假设您有一个名为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;
}

错误信息指出在赋值过程中数组的大小不相同。有几种方法可以解决这个问题。在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文档讨论了调整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;
}