【问题标题】:How do you 'realloc' in C++?你如何在 C++ 中“重新分配”?
【发布时间】:2020-12-17 16:57:21
【问题描述】:

我如何在 C++ 中realloc?语言中似乎缺少它 - 有 newdelete 但没有 resize

我需要它,因为当我的程序读取更多数据时,我需要重新分配缓冲区来保存它。我不认为deleteing 旧指针和newing 一个新的、更大的指针是正确的选择。

【问题讨论】:

标签: c++ new-operator realloc delete-operator


【解决方案1】:

正确的选择可能是使用为您完成工作的容器,例如 std::vector

newdelete 无法调整大小,因为它们分配的内存刚好足以容纳给定类型的对象。给定类型的大小永远不会改变。有new[]delete[],但几乎没有理由使用它们。

无论如何,realloc 在 C 中所做的很可能只是 mallocmemcpyfree,尽管如果有足够的连续空闲内存可用,内存管理器可以做一些聪明的事情。

【讨论】:

  • 那么在 C++ 中实现增长缓冲区的正确方法是什么?目前我有char *buf = (char *)malloc(size),然后当它变得太小时我做buf = realloc(size + more_size); size += more_size。如何使用矢量来做到这一点?
  • @bodacydo:不要实现增长缓冲区,只需使用std::vector - 它会在需要时自动增长,您可以根据需要预先分配内存(reserve())。
  • 使用 std::vector。这就是它的用途。在 C++ 中,没有任何理由自己使用 new/delete/new[]/delete[],除非您明确编写资源管理类。
  • @bod:是的,可以。 (顺便说一句,std::string 也可以。)
  • 听起来像thevector.resize(previous_size + incoming_size),然后是memcpy(或类似的)变成&thevector[previous_size],这就是您所需要的。保证向量的数据“像数组”一样存储。
【解决方案2】:

使用 ::std::vector!

Type* t = (Type*)malloc(sizeof(Type)*n) 
memset(t, 0, sizeof(Type)*m)

变成

::std::vector<Type> t(n, 0);

然后

t = (Type*)realloc(t, sizeof(Type) * n2);

变成

t.resize(n2);

如果你想将指针传递给函数,而不是

Foo(t)

使用

Foo(&t[0])

这是绝对正确的 C++ 代码,因为 vector 是一个智能 C 数组。

【讨论】:

  • memset 行是否应该是 memset(t, 0, sizeof(T) * n);? n 而不是 m?
  • @anthom 是的。真的应该是Type* t = static_cast&lt;Type*&gt;(malloc(n * sizeof *t));
  • 使用 C++11 现在可以使用 t.data() 而不是 &amp;t[0]
  • 你怎么能删除这个?
  • @a3mlord:你什么意思?让它超出范围,它就消失了。
【解决方案3】:

在 C++ 中调整大小很尴尬,因为可能需要调用构造函数和析构函数。

我认为在 C++ 中你不能有一个 resize[] 运算符与 new[]delete[] 一起使用,我认为这没有根本原因,它做了类似的事情:

newbuf = new Type[newsize];
std::copy_n(oldbuf, std::min(oldsize, newsize), newbuf);
delete[] oldbuf;
return newbuf;

显然oldsize 会从一个秘密位置检索,同样是在delete[] 中,Type 将来自操作数的类型。 resize[] 在类型不可复制的情况下会失败 - 这是正确的,因为这些对象根本无法重新定位。最后,上面的代码在分配对象之前默认构造对象,这是您不希望的实际行为。

newsize &lt;= oldsize 有一个可能的优化,可以为新缩小的数组“结束”后的对象调用析构函数,并且不执行任何其他操作。标准必须定义是否需要这种优化(就像当你 resize() 一个向量时一样)、允许但未指定、允许但依赖于实现或禁止。

然后你应该问自己的问题是,“提供这个真的有用吗,因为 vector 也这样做,并且专门设计用于提供可调整大小的容器(连续内存 - 省略了该要求在 C++98 中但在 C++03 中已修复),这比具有 C++ 做事方式的数组更适合?”

我认为答案被广泛认为是“不”。如果您想以 C 方式进行可调整大小的缓冲区,请使用 C++ 中提供的malloc / free / realloc。如果您想以 C++ 方式进行可调整大小的缓冲区,请使用向量(或 deque,如果您实际上不需要连续存储)。不要尝试通过将new[] 用于原始缓冲区来混合两者,除非您正在实现类似矢量的容器。

【讨论】:

    【解决方案4】:

    这是一个 std::move 示例,它实现了一个带有 realloc 的简单向量(每次达到限制时*2)。如果有比我下面的副本做得更好的方法,请告诉我。

    编译为:

      g++ -std=c++2a -O2 -Wall -pedantic foo.cpp
    

    代码:

    #include <iostream>
    #include <algorithm>
    
    template<class T> class MyVector {
    private:
        T *data;
        size_t maxlen;
        size_t currlen;
    public:
        MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
        MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }
    
        MyVector<T> (const MyVector& o) {
            std::cout << "copy ctor called" << std::endl;
            data = new T [o.maxlen];
            maxlen = o.maxlen;
            currlen = o.currlen;
            std::copy(o.data, o.data + o.maxlen, data);
        }
    
        MyVector<T> (const MyVector<T>&& o) {
            std::cout << "move ctor called" << std::endl;
            data = o.data;
            maxlen = o.maxlen;
            currlen = o.currlen;
        }
    
        void push_back (const T& i) {
            if (currlen >= maxlen) {
                maxlen *= 2;
                auto newdata = new T [maxlen];
                std::copy(data, data + currlen, newdata);
                if (data) {
                    delete[] data;
                }
                data = newdata;
            }
            data[currlen++] = i;
        }
    
        friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
            auto s = o.data;
            auto e = o.data + o.currlen;;
            while (s < e) {
                os << "[" << *s << "]";
                s++;
            }
            return os;
        }
    };
    
    int main() {
        auto c = new MyVector<int>(1);
        c->push_back(10);
        c->push_back(11);
    }
    

    【讨论】:

      猜你喜欢
      • 2015-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 2020-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多