首先,根据C++标准,使用delete分配的任何内容new[]都是未定义的行为.
在Visual C++ 7中,这种配对可能导致两种后果之一.
如果类型new []'ed有简单的构造函数和析构函数VC++只是使用new而不是new[]和使用delete该块工作正常 - new只调用"分配内存",delete只调用"空闲内存".
如果new []'ed类型有一个非平凡的构造函数或析构函数,则无法完成上述技巧 - VC++ 7必须调用恰当数量的析构函数.因此它预先在数组中size_t存储元素的数量.现在,地址返回的地址new[]到第一个元素,而不是块的开头.因此,如果delete使用它只调用第一个元素的析构函数和调用"空闲内存",其地址不同于"分配内存"返回的地址,这导致HeapFree()内部的一些错误指示我怀疑是指堆腐败.
然而,每个人都可以阅读使用deleteafter new[]导致内存泄漏的错误陈述.我怀疑任何大小的堆损坏都比仅为第一个元素调用析构函数并且可能没有调用的析构函数没有释放堆分配的子对象这一事实重要得多.
如何使用delete之后new[]可能只会导致某些C++实现中的内存泄漏?
由于未定义的行为,许多不好的事情发生并且继续发生(或者不知道,谁知道,任何事情都可能发生).据我所知,这是为了让编译器进行优化留下一些摆动空间,也可能使C++更容易移植到不同的平台和架构.然而,由未定义的行为引起的问题似乎太大而无法通过这些论证来证明.未定义行为的其他参数是什么?如果没有,为什么还存在未定义的行为?
编辑为我的问题添加一些动机:由于使用较少C++的几个糟糕经历 - 狡猾的同事,我已经习惯了使我的代码尽可能安全.断言每一个论点,严谨的正确性以及类似的东西.我试图离开,因为小房间可能以错误的方式使用我的代码,因为经验表明,如果有漏洞,人们会使用它们,然后他们会打电话给我,说我的代码很糟糕.我认为让我的代码尽可能安全是一种好的做法.这就是为什么我不明白为什么存在未定义的行为.有人可以给我一个未定义行为的例子,这些行为在运行时或编译时无法检测到而没有相当大的开销吗?
void main(void)
{
int x,y,z;
x=y=z=1;
z = x && y && ++z;//is this fine?
}
Run Code Online (Sandbox Code Playgroud)
我最近开始阅读关于序列点的东西,但我无法弄清楚上面的代码示例是否正常.我知道&&运算符引入了一个序列点,所以我不太确定表达式z = x && y && ++ z的行为.有人请告诉我正确的答案.
注意:这是一个自我问答,并且针对“Let us C”一书宣传的错误信息进行了更直观的提问。另外,请让我们不要讨论C++,这个问题是关于 C 的。
我正在阅读 Yashwant Kanetkar 的书“Let us C”。
书中有如下例子:
#include <stdio.h>
int main(void) {
int a = 1;
printf("%d %d %d", a, ++a, a++);
}
Run Code Online (Sandbox Code Playgroud)
作者声称这段代码应该输出3 3 1:
令人惊讶的是,它输出
3 3 1. 这是因为 C 的调用约定是从右到左。也就是说,首先1通过表达式a++,然后a增加到2。然后结果++a就通过了。即 a 增加到 3 然后通过。最后,传递 a 的最新值,即 3。因此按从右到左的顺序1, 3, 3通过。一旦printf( ) 收集它们,它就会按照我们要求它打印它们的顺序(而不是传递它们的顺序)打印它们。这样3 3 1就打印出来了。
但是,当我编译代码并使用 运行它时clang,结果是1 2 2 …
c undefined-behavior sequence-points language-lawyer order-of-execution
假设我有这样的第一个结构:
typedef struct {
int ivalue;
char cvalue;
}
Foo;
Run Code Online (Sandbox Code Playgroud)
第二个:
typedef struct {
int ivalue;
char cvalue;
unsigned char some_data_block[0xFF];
}
Bar;
Run Code Online (Sandbox Code Playgroud)
现在让我们说我做了以下事情:
Foo *pfoo;
Bar *pbar;
pbar = new Bar;
pfoo = (Foo *)pbar;
delete pfoo;
Run Code Online (Sandbox Code Playgroud)
现在,当我调用delete操作符时,它释放了多少内存?
sizeof(int) + sizeof(char)
Run Code Online (Sandbox Code Playgroud)
要么
sizeof(int) + sizeof(char) + sizeof(char) * 0xFF
Run Code Online (Sandbox Code Playgroud)
?
如果这是由于铸造的第一种情况,有没有办法防止这种内存泄漏发生?
注意:请不要回答"使用C++多态"或类似的,我使用这种方法是有原因的.
C指针(始终)是否从有效的地址存储器开始?例如,如果我有以下代码:
int *p;
*p = 5;
printf("%i",*p); //shows 5
Run Code Online (Sandbox Code Playgroud)
为什么这段代码起作用?根据我读过的书,他们说一个指针始终需要一个有效的地址存储器,并给出以下类似的示例:
int *p;
int v = 5;
p = &v;
printf("%i",*p); //shows 5
Run Code Online (Sandbox Code Playgroud) 以下代码可以编译并完美运行:
typedef struct n {
char value;
struct n* next;
} node;
void insert_new_node(node** head, char new_value)
{
node* new_node = malloc(sizeof(node*));
new_node->value = new_value;
new_node->next = NULL;
if(*head == NULL)
{
*head = new_node;
}
else
{
node* current = *head;
while(current->next != NULL)
{
current = current->next;
}
current->next = new_node;
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是-请注意,我实际上实际上只是为指向结构的指针分配了空间,而不是为结构本身分配了空间(ref:)node* new_node = malloc(sizeof(node*));。所以我的问题是,该结构数据实际存储在哪里,如果存储在堆中,它将如何工作?
当我创建一个动态数组时:
int *arr = (int *) malloc( 4 * sizeof(int) );
Run Code Online (Sandbox Code Playgroud)
所以它应该包含 4 个整数(对于空间问题可能还有 2 或 3 个),但为什么这样做:
for ( int x = 0; x < 30000; x++) {
arr[x] = x;
}
Run Code Online (Sandbox Code Playgroud)
我的意思是不应该有 30.000 个变量的空间,而且它工作得很好,可能是什么原因?它是否像 c++ std::vector 一样自动重新分配,或者我如何理解它?
如果我将循环范围设置为 50.000,它会崩溃,但它甚至应该像索引 a[100] 或之前那样崩溃,因为数组有 4 个元素。
如果这很重要,我正在使用 gnu/linux。
我非常努力地理解它。
请帮忙