好吧,我想我们都同意以下代码所发生的事情是未定义的,具体取决于传递的内容,
void deleteForMe(int* pointer)
{
delete[] pointer;
}
Run Code Online (Sandbox Code Playgroud)
指针可以是各种不同的东西,因此delete[]对它执行无条件是未定义的.但是,让我们假设我们确实传递了一个数组指针,
int main()
{
int* arr = new int[5];
deleteForMe(arr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,在这种情况下,指针是一个数组,谁知道这个?我的意思是,从语言/编译器的角度来看,它不知道arr数组指针是否指向单个int的指针.哎呀,它甚至不知道是否arr是动态创建的.但是,如果我做以下事情,
int main()
{
int* num = new int(1);
deleteForMe(num);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
操作系统足够聪明,只能删除一个int,而不是通过删除超出该点的其余内存来进行某种类型的"杀戮狂欢"(与strlen非\0终结字符串形成对比- 它将一直持续到它点击0).
那么他们的工作是记住这些东西吗?操作系统是否在后台保留某种类型的记录?(我的意思是,我意识到我开始这篇文章时说过发生的事情是未定义的,但事实是,'杀戮狂欢'的情况不会发生,所以因此在实际世界中有人记得.)
在将它用于数组时,是否可以在便携式代码中实际使用新的放置?
看来你从new []返回的指针并不总是和你传入的地址相同(5.3.4,标准中的注释12似乎证实这是正确的),但是我不知道你是怎么回事如果是这种情况,可以为数组分配一个缓冲区.
以下示例显示了该问题.使用Visual Studio编译,此示例导致内存损坏:
#include <new>
#include <stdio.h>
class A
{
public:
A() : data(0) {}
virtual ~A() {}
int data;
};
int main()
{
const int NUMELEMENTS=20;
char *pBuffer = new char[NUMELEMENTS*sizeof(A)];
A *pA = new(pBuffer) A[NUMELEMENTS];
// With VC++, pA will be four bytes higher than pBuffer
printf("Buffer address: %x, Array address: %x\n", pBuffer, pA);
// Debug runtime will assert here due to heap corruption
delete[] pBuffer;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
查看内存,编译器似乎使用缓冲区的前四个字节来存储其中项目数的计数.这意味着因为缓冲区sizeof(A)*NUMELEMENTS很大,所以数组中的最后一个元素被写入未分配的堆中.
所以问题是你能找到你的实现需要多少额外的开销来安全地使用placement new []吗?理想情况下,我需要一种可在不同编译器之间移植的技术.请注意,至少在VC的情况下,不同类的开销似乎不同.例如,如果我删除示例中的虚拟析构函数,则new []返回的地址与我传入的地址相同.
我想使用malloc声明一个二维数组。在互联网上查找时,所有网站都告诉您声明一个int **指针,然后使用malloc首先将各个指针分配给1d数组,然后再次使用malloc为各个int分配空间。我的怀疑是,以这种方式声明的数组不会将其元素保存在连续的内存地址中。虽然以下方法仅使用一个malloc语句并动态分配2d数组,但所有地址均根据需要是连续的。因此,以下内容不是动态分配2d数组的正确方法吗?
#include <stdio.h>
int main(){
int (*p)[2] = malloc(3 * sizeof *p);
int i;
int j;
//All addresses printed here are contiguous
for(i=0; i<3; i++){
for(j=0; j<2; j++){
printf("%d\t", &p[i][j]);
}
printf("\n");
}
}
Run Code Online (Sandbox Code Playgroud) 我们和我的朋友一起制作了一个带有覆盖 new 和 new[] 运算符的程序。我发现当我尝试使用以下代码创建字符串数组时:
string* Test1 = new string[10];
Run Code Online (Sandbox Code Playgroud)
函数返回无效指针(通常它的值向前移动 8 位,我正在将程序编译到 x64 平台)。我们的 new[] 函数看起来像这样:
void* operator new[] (size_t e)
{
void* Test2 = operator new(e);
return Test2;
}
Run Code Online (Sandbox Code Playgroud)
在返回前用调试器运行程序时,指针的Test2值为 0x0000000009dfaa90,但值Test1变为 0x0000000009dfaa98。
这种情况只发生在字符串类型中。我试过对“int[10]”、“string* [10]”和我的一个类的对象做同样的事情,但只有在处理字符串时才会出现问题,还有代码:
string* Test1 = new string;
Run Code Online (Sandbox Code Playgroud)
工作得很好。
有人可以解释一下为什么会发生这种情况以及如何使其正常工作吗?
PS:我们使用的是 Visual Studio 2012 专业版
编辑:我刚刚测试了它未被覆盖,new[]并且在创建字符串表时它的工作方式相同(返回的指针不是函数尝试的指针return),所以它似乎不是问题。有人能解释一下为什么指针的值只对字符串数组改变,如果似乎没有任何其他指令可以改变它,它会如何改变?
我正在阅读有关内存的 C++ Primer Plus, 12.1.3,以及有关析构函数的一些内容真的让我感到困惑。
//Here is a default construtor of String class
String::String()
{
len = 0;
str = new char[1];
str[0] = '\0';
}
Run Code Online (Sandbox Code Playgroud)
书上说,使用str = new char[1]not str = new char,两种方式分配相同的内存,但第二种与析构函数不兼容。此外,书中说以下3种方式不好,因为它们与“删除”不兼容
char words[15] = "bad idea";
char *p1 = words;
char *p2 = new char;
char *p3;
delete [] p1; //undefined, so don't do it
delete [] p2; //undefined, so don't do it
delete [] p3; //undefined, so don't do it
Run Code Online (Sandbox Code Playgroud)
我不知道这 3 种方式有什么不同,有人可以向我解释一下吗?非常感谢。
c++ ×4
arrays ×3
new-operator ×2
pointers ×2
c ×1
class ×1
destructor ×1
malloc ×1
overhead ×1
overriding ×1
portability ×1
string ×1