我和朋友一起制作了一个覆盖new和new []运算符的程序。 我发现当我尝试用这段代码创建字符串数组时:
string* Test1 = new string[10];
函数返回无效指针(通常它的值向前移动8位,我正在将程序编译到x64平台)。 我们的新[]函数看起来像这样:
void* operator new[] (size_t e)
{
void* Test2 = operator new(e);
return Test2;
}
在返回之前使用调试器运行程序时,指针Test2
的值为0x0000000009dfaa90,但Test1
的值变为0x0000000009dfaa98。
这种情况只发生在字符串类型中。我试过用“int [10]”,“string * [10]”和我的一个类的对象做同样的事情,但问题只在处理字符串时发生,同样,代码:
string* Test1 = new string;
完美无缺。
有人可以解释一下为什么会发生这种情况以及如何使其正常工作吗?
PS:我们正在使用Visual Studio 2012 Proffesional
编辑:我刚刚测试了它非重写new[]
并且在创建字符串表时它的工作方式相同(返回指针不是函数尝试return
的指针),所以它似乎不是问题。有人可以解释一下为什么指针的值只对字符串数组改变,如果似乎没有任何其他指令可以改变它,它会如何改变?
答案 0 :(得分:1)
答案是new/delete
和new[]/delete[]
不同。这对你来说可能不会让你感到意外,但另一个令人惊讶的消息(双关语并非意图)是new
运算符和operator new
不同。
以下是测试问题的示例代码(您可以将tested_type
的typedef更改为:)
#include <iostream>
#include <vector>
#include <string>
typedef std::string tested_type;
void* Test2;
size_t allocated_mem_size;
void* operator new[] (size_t e)
{
void* retaddr = operator new(e);
Test2 = retaddr;
allocated_mem_size = e;
return retaddr;
}
int _tmain(int argc, _TCHAR* argv[])
{
void* Test1 = new tested_type[10];
std::cout << "sizeof(tested_type)*10 is " << sizeof(tested_type)*10 << "\n"
<< "Test1 is " << Test1 << "\n"
<< "Test2 is " << Test2 << "\n"
<< "operator new[] was called with e == " << allocated_mem_size << "\n"
<< "What's in the missing bytes? " << *(size_t*)Test2 << "\n";
}
我机器上的输出是:
sizeof(tested_type)*10 is 280
Test1 is 0085D64C
Test2 is 0085D648
operator new[] was called with e == 284
What's in the missing bytes? 10
(注意 - 我有一个32位编译器)
如果我们将tested_type
更改为int,我们有:
sizeof(tested_type)*10 is 40
Test1 is 0070D648
Test2 is 0070D648
operator new[] was called with e == 40
What's in the missing bytes? 3452816845
现在,如果我们将tested_type
更改为std::vector<int>
,我们就有
sizeof(tested_type)*10 is 160
Test1 is 004AD64C
Test2 is 004AD648
operator new[] was called with e == 164
What's in the missing bytes? 10
现在我们在这里看到一个模式:添加的额外字节数等于分配的元素数。此外,添加字节的唯一时间是类型是非平凡的......
就是这样!
调整地址的原因是new[]
想要存储元素数量。我们需要在某些情况下而不是在其他情况下存储元素数量的原因是delete[]
调用析构函数,而delete[]
(但不是delete
只调用析构函数单个元素)必须以某种方式知道它必须销毁多少元素。不需要为int
这样的基本类型调用析构函数,因此new[]
不存储有多少。{/ p>
(另外,我推荐std::vector
- 它只是有效)