简体   繁体   中英

Vector containing a partial subset of another vector both pointing to the same memory

I have a matrix class that stores its data in a std::vector :

std::vector<double> mData(mRows*mCols);

The class has a method to extract a column from this matrix:

std::vector<double> matrix::getCol(const int &n) const
{
    std::vector<double> Col(mRows);

    for(int ii = 0; ii < mRows; ii++)
    {
        Col[ii] = mData[n*mRows + ii];
    }

    return Col;
}

I would like to have this method return a reference to a vector that is a subset of mData . Is something like this possible?

std::vector<double>& matrix::getCol(const int &n)
{
    std::vector<double> Col(mRows);
    &Col[0] = &mData[n*mRows];

    return Col;
}

The reason that I am interested in this is that I would like to use this method in assignment:

matrix A(rows,cols);
std::vector<double> newCol(rows);
A.getCol(0) = newCol;

One way is to store the matrix's data into a std::vector<std::vector<double> > . Then, the implementation of matrix::getCol() is straightforward.

class matrix {
public:
    matrix(int row, int col)
        : mData(col, std::vector<double>(row))
    {
    }
    std::vector<double>& getCol(int n)
    {
        return mData[n];
    }
private:
    std::vector<std::vector<double> > mData;
};

matrix A(rows, cols);
std::vector<double> newCol(rows);
A.getCol(0) = newCol; // works fine

Another way is defining matrix::setCol() instead.

Another alternative is to write a array_ref class, which contains a pointer to data and size, but does not own the data. It would allow modifications to elements, but no inserts or erases. Then you could construct it to point at regular arrays, vectors, of subsets of either. This is actually a fairly common practice with strings having a string_ref class, that might refer to the contents of a std::string , or a char* , or a char[N] . It would be fairly simple, and requires virtually no changes to your existing matrix class.

//untested sample
template<class T>
struct array_ref {
    typedef T value_type;
    typedef T& reference;
    typedef T* pointer;
    typedef ptrdiff_t difference_type;
    typedef size_t size_type;
    typedef T* iterator;
    typedef const T* const_iterator;

    array_ref() : data(nullptr), len(0) {}
    array_ref(T* data_, size_t len_) : ptr(data_), len(len_) {}
    T& at(size_t index) {assert_range(index); return ptr[index];}
    const T& at(size_t index) const {assert_range(index); return ptr[index];}
    T* begin() {return ptr;}
    const T* begin() const {return ptr;}
    T* end() {return ptr+len;}
    const T* end() const {return ptr+len;}
    T* data() {return ptr;}
    const T* data() const {return ptr;}
    T& operator[](size_t index) {return ptr[index];}
    const T& operator[](size_t index) const {return ptr[index];}
    size_t size() const {return len;}
private: 
    void assert_range(size_t index) const
    {if (index>=len) throw std::out_of_range("out of range");}
    T* ptr;
    size_t len;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM