c++:将数组连接在一起-是否可能使用指针而不复制



在标题中是否可以将多个数组连接在一起而不需要复制和仅使用指针?我花费了大量的计算时间将较小的数组复制到较大的数组。注意我不能使用向量,因为umfpack(一些矩阵求解库)不允许我这样做,或者我不知道怎么做。

例如:

int n = 5;
// dynamically allocate array with use of pointer
int *a = new int[n];

// define array pointed by *a as [1 2 3 4 5]
for(int i=0;i<n;i++) {
    a[i]=i+1;
}

// pointer to array of pointers ???  --> this does not work
int *large_a = new int[4];
for(int i=0;i<4;i++) {
    large_a[i] = a;
}

注意:我已经知道了一个简单的解决方案,那就是迭代地将它们复制到一个新的大数组中,但是如果不需要复制整个程序持续时间内存储的重复块,那就更好了。我现在还在学习阶段。

感谢大家的阅读

在标题中是否有可能将多个数组连接在一起,而不需要复制和仅使用指针?

简而言之,没有。

指针只是一个进入内存的地址——就像街道地址一样。你不能仅仅通过复制他们的地址就把两个房子搬到一起。你也不能通过改变地址把两所房子搬到一起。更改地址并不会移动房子,它指向一个新房子。

注意我不能使用向量,因为umfpack(一些矩阵求解库)不允许我这样做,或者我不知道怎么做。

大多数情况下,当期望一个数组时,您可以传递std::vector的第一个元素的地址。

std::vector a = {0, 1, 2}; // C++0x initialization
void c_fn_call(int*);
c_fn_call(&a[0]);

这可以工作,因为vector保证其内容的存储始终是连续的。

然而,当你从vectorinserterase一个元素时,它使来自它的指针和迭代器无效。如果一个元素被分配的存储空间必须改变,那么你从元素的地址中获得的任何指针都不再指向vector

No。两个数组的内存不一定是连续的,所以没有办法在不复制的情况下连接它们。数组元素必须在连续内存中…

我可能会使用memcpy/memmove,它仍然会复制内存,但至少它已经被编译器供应商优化和测试过了。

当然,"真正的"c++方法是使用标准容器和迭代器。如果你的内存像这样分散在各处,我觉得使用链表是一个更好的主意,除非你要做很多随机访问操作。 另外,请记住,如果您使用指针和动态分配的数组而不是标准容器,则更容易导致内存泄漏和其他问题。我知道有时候你别无选择,但只是说。

如果你想连接数组而不复制元素,同时你想使用下标操作符(即[])访问元素,那么如果不编写一个封装所有这些功能的类,这是不可能的。

我写了下面的类,考虑最少,但它展示了基本的思想,如果你想让它具有目前没有的功能,你可以进一步编辑它。也应该有一些错误,我没有写,只是为了让它看起来更短,但我相信你会理解代码,并相应地处理错误情况。

template<typename T>
class joinable_array
{
     std::vector<T*>     m_data;
     std::vector<size_t> m_size;
     size_t              m_allsize;
   public: 
       joinable_array() : m_allsize() { }
       joinable_array(T *a, size_t len) : m_allsize() { join(a,len);}
       void join(T *a, size_t len)
       {
           m_data.push_back(a);
           m_size.push_back(len);
           m_allsize += len;
       }
       T & operator[](size_t i)  
       {
            index ix = get_index(i);
            return m_data[ix.v][ix.i];
       }
       const T & operator[](size_t i) const
       {
            index ix = get_index(i);
            return m_data[ix.v][ix.i];
       }
       size_t size() const { return m_allsize; }
  private:
       struct index
       {
           size_t v;
           size_t i;
       };
       index get_index(size_t i) const
       {
          index ix = { 0,  i};
          for(auto it = m_size.begin(); it != m_size.end(); it++)
          {
                if ( ix.i >= *it ) { ix.i -= *it; ix.v++; }
                else break;
          }
          return ix;
       }
};

这里有一个测试代码:

#define alen(a) sizeof(a)/sizeof(*a)
int main() {
        int a[] = {1,2,3,4,5,6};
        int b[] = {11,12,13,14,15,16,17,18};
        joinable_array<int> arr(a,alen(a));
        arr.join(b, alen(b));
        arr.join(a, alen(a)); //join it again!
        for(size_t i = 0 ; i < arr.size() ; i++ )
            std::cout << arr[i] << " ";
}
输出:

1 2 3 4 5 6 11 12 13 14 15 16 17 18 1 2 3 4 5 6 

在线演示:http://ideone.com/VRSJI

如何正确使用:

template<class T, class K1, class K2>
class JoinArray {
    JoinArray(K1 &k1, K2 &k2) : k1(k1), k2(k2) { }
    T operator[](int i) const { int s = k1.size(); if (i < s) return k1.operator[](i); else return k2.operator[](i-s); }
    int size() const { return k1.size() + k2.size(); }
 private:
    K1 &k1;
    K2 &k2;
 };
 template<class T, class K1, class K2>
 JoinArray<T,K1,K2> join(K1 &k1, K2 &k2) { return JoinArray<T,K1,K2>(k1,k2); }
 template<class T>
 class NativeArray
 {
     NativeArray(T *ptr, int size) : ptr(ptr), size(size) { }
     T operator[](int i) const { return ptr[i]; }
     int size() const { return size; }
  private:
     T *ptr;
     int size;
  };
 int main() {
    int array[2] = { 0,1 };
    int array2[2] = { 2,3 };
    NativeArray<int> na(array, 2);
    NativeArray<int> na2(array2, 2);
    auto joinarray = join(na,na2);
}

指向指针的指针变量必须这样声明。这是通过在其名称前面放置一个额外的星号来完成的。因此,int **large_a = new int*[4];你的large_a去找一个指针,而你已经把它定义为一个指向int的指针。它应该被定义(声明)为指向指针变量的指针。就像int **large_a;一样。

最新更新