C++语句的 Big-O 是 O(1) 还是 O(n)'delete [] Q;'?
Is Big-O of the C++ statement 'delete [] Q;' O(1) or O(n)?
标题不言自明。很简单的问题。我想是0 (n),但我想在明天期末考试前验证一下。
简短的回答是…这取决于.
如果Q
是指向具有析构函数的对象数组的指针,则delete[] Q
需要调用所有这些析构函数。这将调用O(n)个析构函数,其中n是数组中元素的数量。另一方面,如果Q
指向一个没有析构函数的对象数组(例如,int
s或简单的struct
s),则不需要调用析构函数,这只需要O(1)时间。
现在请注意,这些析构函数不必每个都在O(1)时间内运行。如果对象是std::vector
对象,那么每个析构函数依次必须触发更多的释放。在不进一步了解这些对象的情况下,我们只能说,如果调用了析构函数,如果析构函数是普通的,则将调用0个析构函数,否则将调用O(n)个析构函数。
但是这忽略了堆分配器如何工作的实现细节。释放一块内存可能需要O(log K)时间,其中K是分配的块的总数,或者可能需要O(1)时间,不管有多少块内存,或者可能需要O(log log K),等等。在不知道分配器是如何工作的情况下,你真的不能确定。
简而言之,如果您只关注在将块交还给内存分配器之前清理对象所需的工作,则如果存储的对象具有析构函数,则调用O(n)个析构函数,否则调用0个析构函数。这些析构函数可能需要相当长的时间才能完成。然后,有将内存块重新引入内存分配器的成本,这可能会占用它自己的时间。
希望这对你有帮助!
我同意这要视情况而定,但是让我们只讨论释放X字节的内存,而不用担心析构函数。
一些内存分配器为"小"(1到500字节)对象保留空闲列表。对列表的插入是O(1)。如果所有线程都有一个空闲列表,那么它需要获取一个互斥锁。获取互斥锁通常涉及到多达1000个"旋转",然后可能是一个系统调用(这是非常昂贵的)。有些分配器使用线程本地存储为每个线程提供空闲列表,因此它们不需要获取互斥锁。
对于中等大小(500到60000字节)的对象,许多分配器将执行块合并。也就是说,它们检查相邻的块是否也是空闲的,然后将2或3个空闲块合并成一个更大的空闲块。合并是0(1),但是它同样需要获取一个互斥锁。
对于大块,一些分配器使用系统调用获得内存。所以释放内存也是一个系统调用。
- enum是C++中的宏变量还是整数变量
- 如果我只是不访问queue_front节点的子节点,而是将它们推到队列中呢?还是BFS吗
- 在命名空间中定义函数还是限定函数
- 运算符C++ "delete []"仅删除 2 个前值
- 架构决策:返回std::future还是提供回调
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 异常属于C++中的线程还是进程
- 在决定是通过参考还是通过价值时,尺寸真的是一个问题吗
- 如何在C++中确定文本文件中的元素是字符还是数字
- 返回值优化:显式移动还是隐式
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 为什么需要知道一个类是平凡的还是有平凡的构造函数
- g++用户定义的动态链接库上的全局new和delete运算符
- 强枚举类型定义:Clang Bug 还是 C++11 标准不确定性?
- 'string.assign(string.data(), 5)' 是明确定义的还是 UB?
- 为什么"delete"关键字不删除节点?
- 在哪里放置我的函数?进入我的母语 Gui 还是进入我的演示者?
- "delete"在 C++ 中实际上做了什么?
- 在接收动态数组或堆对象时,我应该使用 delete 还是 delete[]
- C++语句的 Big-O 是 O(1) 还是 O(n)'delete [] Q;'?