我完全混淆了在C++中删除东西的问题如果我声明了一个对象数组并且我使用了该clear()函数.我可以确定内存已经发布了吗?
例如 :
tempObject obj1;
tempObject obj2;
vector<tempObject> tempVector;
tempVector.pushback(obj1);
tempVector.pushback(obj2);
Run Code Online (Sandbox Code Playgroud)
我可以安全地打电话清除以释放所有内存吗?或者我是否需要逐个删除才能删除?
tempVector.clear();
Run Code Online (Sandbox Code Playgroud)
如果将此场景更改为对象指针,答案是否与上述相同?
vector<tempObject> *tempVector;
//push objects....
tempVector->clear();
Run Code Online (Sandbox Code Playgroud) 考虑一个简单的程序:
int main() {
int* ptr = nullptr;
delete ptr;
}
Run Code Online (Sandbox Code Playgroud)
对于GCC(7.2),在结果程序中有call关于的指令operator delete.对于Clang和Intel编译器,没有这样的指令,空指针删除被完全优化(-O2在所有情况下).你可以在这里测试:https://godbolt.org/g/JmdoJi.
我想知道这样的优化能否以某种方式与GCC一起开启?(我更广泛的动机源于自定义swapvs std::swap可移动类型的问题,其中删除空指针可能代表第二种情况下的性能损失; 有关详细信息,请参阅/sf/answers/3198249771/.)
UPDATE
为了澄清我对这个问题的动机:如果我在移动赋值运算符和某个类的析构函数中使用delete ptr;无if (ptr)保护,那么该类的对象将产生3个GCC指令.这可能是相当大的性能损失,例如,在对这些对象的数组进行排序时.std::swapcall
此外,我可以if (ptr) delete ptr;在任何地方写作,但是想知道,这是否也不能成为性能损失,因为delete表达式也需要检查ptr.但是,在这里,我想,编译器只会生成一个检查.
此外,我真的很喜欢delete没有后卫的可能性,这对我来说是一个惊喜,它可以产生不同的(表现)结果.
UPDATE
我只是做了一个简单的基准测试,即排序对象,它们delete在移动赋值运算符和析构函数中调用.来源是:https://godbolt.org/g/7zGUvo
std::sort使用GCC 7.1测量的运行时间和-O2Xeon E2680v3上的标志:
链接代码中存在一个错误,它会比较指针,而不是指向值.更正结果如下:
if后卫:让我们说我有这样的功能:
int main()
{
char* str = new char[10];
for(int i=0;i<5;i++)
{
//Do stuff with str
}
delete[] str;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
str如果我要结束程序,为什么还需要删除?如果我要退出,我不在乎那个记忆是否会到达满是独角兽的土地,对吧?
这只是好习惯吗?
它有更深的后果吗?
Cosider以下代码:
class Foo
{
Monster* monsters[6];
Foo()
{
for (int i = 0; i < 6; i++)
{
monsters[i] = new Monster();
}
}
virtual ~Foo();
}
Run Code Online (Sandbox Code Playgroud)
什么是正确的析构函数?
这个:
Foo::~Foo()
{
delete [] monsters;
}
Run Code Online (Sandbox Code Playgroud)
或这个:
Foo::~Foo()
{
for (int i = 0; i < 6; i++)
{
delete monsters[i];
}
}
Run Code Online (Sandbox Code Playgroud)
我目前有最重要的构造函数,一切都在工作,但当然我看不出它是否恰好泄漏...
就个人而言,我认为考虑到我在做什么,第二个版本更合乎逻辑.无论如何,这样做的"正确"方法是什么?
运营商的时间复杂度是delete[]多少?
我的意思是它是如何实现的 - 它是否迭代数组中的所有元素并为每个元素调用析构函数?
此运算符是否对基本类型(int等)和用户定义的类型执行相同操作?
为什么非放置new表达式和delete表达式实现为内置语言而不是常规函数?
如果我们有...
一种向OS请求/回馈内存的方法
一种显式调用构造函数的方法(放置new)
一种显式调用析构函数的方法(~T())
...为什么不能放置new,delete只是标准库中的常规功能?例:
template <typename T, typename... Ts>
T* library_new(Ts&&... xs)
{
auto* ptr = /* request enough memory for `T` from OS */;
new (ptr) T(std::forward<Ts>(xs)...);
return ptr;
}
template <typename T>
void library_delete(T* ptr)
{
ptr->~T();
/* reclaim memory for `T` from OS */
}
Run Code Online (Sandbox Code Playgroud) 上一个标题:"我必须替换全局运算符new和delete以更改第三方代码中的内存分配策略吗?"
简短的故事: 我们需要在不改变源代码的情况下替换第三方库中的内存分配技术.
很长的故事:
考虑使用大量动态分配的内存绑定应用程序(可能是几乎所有可用的系统内存).我们使用专门的分配器,并在任何地方使用它们(shared_ptr容器等).我们对应用程序中分配的每个字节内存都有完全的控制和功能.
此外,我们需要链接第三方帮助程序库.那个讨厌的家伙使得分配在一些标准的方法,使用默认的运营商new,new[],delete和delete[]或malloc或别的东西非标准(让我们一概而论说我们不知道这个库如何管理它的堆分配).
如果这个帮助程序库进行足够大的分配,我们可能会出现硬盘抖动,内存碎片和对齐问题,内存bad_alloc不足以及各种问题.
我们不能(或不想)更改库源代码.
第一次尝试:
我们之前从未在发布版本中遇到过这种不圣洁的"hack".使用覆盖运算符的第一次测试new工作正常,但以下情况除外:
问题:
malloc或者new?此签名列表是否完整?(并且没有其他事情我们必须实施):
void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw();
void* operator new (std::size_t size, void* ptr) throw();
void* operator new[] (std::size_t size) throw (std::bad_alloc);
void* operator new[] (std::size_t size, const std::nothrow_t& nothrow_value) throw(); …Run Code Online (Sandbox Code Playgroud)在C++中删除这样的对象有什么不对吗?
MyCls* c = new MyCls();
void* p = (void*)c;
delete (MyCls*)p;
Run Code Online (Sandbox Code Playgroud) 我在C++ 03标准中找到了以下片段5.3.5 [expr.delete] p3:
在第一个备选(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,静态类型应具有虚拟析构函数或者行为未定义.在第二个备选(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义.
快速回顾静态和动态类型:
struct B{ virtual ~B(){} };
struct D : B{};
B* p = new D();
Run Code Online (Sandbox Code Playgroud)
静态类型p是B*,而动态类型*p是D,1.3.7 [defns.dynamic.type]:
[ 例如:如果一个
p静态类型为"指向"的指针class B指向一个对象class D,B该表达式的动态类型*p是"D."]
现在,再次查看顶部的引用,这意味着如果我正确的话,下面的代码会调用未定义的行为,无论是否存在virtual析构函数:
struct B{ virtual ~B(){} };
struct D : B{};
B* p = new D[20];
delete [] p; // undefined behaviour here …Run Code Online (Sandbox Code Playgroud) 考虑:
delete new std :: string [2];
delete [] new std :: string;
Run Code Online (Sandbox Code Playgroud)
每个人都知道第一个是错误.如果第二个不是错误,我们就不需要两个不同的运算符.
现在考虑:
std :: unique_ptr <int> x (new int [2]);
std :: unique_ptr <int> y (new int);
Run Code Online (Sandbox Code Playgroud)
是否x知道使用delete[]而不是 delete?
背景:当我认为指针的数组类型限定将是一个方便的语言功能时,这个问题浮现在我脑海中.
int *[] foo = new int [2]; // OK
int * bar = new int; // OK
delete [] foo; // OK
delete bar; // OK
foo = new int; // Compile error
bar = new int[2]; // Compile error
delete foo; …Run Code Online (Sandbox Code Playgroud) c++ ×10
delete-operator ×10
new-operator ×2
pointers ×2
arrays ×1
c++11 ×1
destructor ×1
gcc ×1
memory ×1
memory-leaks ×1
null ×1
shared-ptr ×1
vector ×1
void ×1