MyCustomObject * object=new MyCustomObject();
Run Code Online (Sandbox Code Playgroud)
假设我的许多类都使用了对象指针,但突然间我想改变指针的内容而不改变地址.
我错误地认为object = new MyCustomObject()会给对象一个新的指针地址吗?我想要新对象而不更改指针地址(是的,我将确保清理旧对象).
Eri*_*hil 13
通常,最好更改对象的属性(通过调用其方法),而不是删除它并创建一个新属性.特别是,您可以通过赋值完全替换对象,例如:
*object = MyCustomObject(); // Replace object with the result of default constructor.
Run Code Online (Sandbox Code Playgroud)
您可以使用对象的现有实例(例如,为此目的定义的某个静态对象)或返回所需对象的函数的结果,而不是默认构造函数.
但是,您可以通过调用其析构函数来删除对象但保留其空间,并且可以使用placement在同一位置创建新对象new:
#include <iostream>
class MyObject
{
public:
MyObject() { std::cout << "I was created at " << (void *) this << ".\n"; }
~MyObject() { std::cout << "Farewell from " << (void *) this << ".\n"; }
};
int main(void)
{
// Allocate space and create a new object.
MyObject *p = new MyObject;
// Destroy the object but leave the space allocated.
p->~MyObject();
// Create a new object in the same space.
p = new (p) MyObject;
// Delete the object and release the space.
delete p;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在调用析构函数和放置之后new,指向旧对象的指针指向新对象,因为它与旧对象位于同一位置.
这是了解内存如何在C++中为对象工作的问题
让我们假设我们有以下对象:
class SimpleObject
{
public:
char name[16];
int age;
};
Run Code Online (Sandbox Code Playgroud)
它的大小将是20.(在大多数平台上).所以在内存中它看起来像这样:
Bytes
name age
0000000000000000|0000|
Run Code Online (Sandbox Code Playgroud)
您可以手动更改内存,以便通过执行以下操作来创建对象:
//Manual assigment
staticMemory[0] = 'F';
staticMemory[1] = 'e';
staticMemory[2] = 'l';
staticMemory[3] = 0;
int* age = reinterpret_cast<int*>(&staticMemory[16]);
*age = 21;
Run Code Online (Sandbox Code Playgroud)
您可以通过执行以下操作来成功创建对象:
printf("In static manual memory the name is %s %d years old\n",
reinterpret_cast<SimpleObject*>(staticMemory)->name
,reinterpret_cast<SimpleObject*>(staticMemory)->age);
Run Code Online (Sandbox Code Playgroud)
哪个输出:
在静态手动记忆中,名字是邪能21岁
由于显而易见的实际原因,这在现实生活中并未使用,但它有助于理解对象的存储方式.
新运算符基本上如下:
根据实现情况,它会更复杂,但想法是一样的.
所以如果构造函数是:
SimpleObject::SimpleObject(const char* name,int age)
{
memcpy(this->name,name,16);
this->age = age;
}
Run Code Online (Sandbox Code Playgroud)
这段代码:
SimpleObject* dynamicObject = new SimpleObject("Charles",31);
Run Code Online (Sandbox Code Playgroud)
几乎相当于:
SimpleObject* dynamicMemoryObject = (SimpleObject*)malloc( sizeof(SimpleObject) );
memcpy(dynamicMemoryObject->name,"Charles",16);
dynamicMemoryObject->age = 31;
Run Code Online (Sandbox Code Playgroud)
正如我所说的那样复杂一点,但想法是一样的.
现在已经了解了这一点,有很多方法可以替换同一内存空间中的对象,最常见的方法是放置new.下面有很多例子:
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <new>
class SimpleObject
{
public:
char name[16];
int age;
SimpleObject(const char* name,int age);
SimpleObject()
{
}
};
SimpleObject::SimpleObject(const char* name,int age)
{
memcpy(this->name,name,16);
this->age = age;
}
//Object in static memory
SimpleObject staticObject;
//20 bytes in static memory
char staticMemory[20];
int main()
{
//Manual assigment
staticMemory[0] = 'F';
staticMemory[1] = 'e';
staticMemory[2] = 'l';
staticMemory[3] = 0;
int* age = reinterpret_cast<int*>(&staticMemory[16]);
*age = 21;
printf("In static manual memory the name is %s %d years old\n",
reinterpret_cast<SimpleObject*>(staticMemory)->name
,reinterpret_cast<SimpleObject*>(staticMemory)->age);
//Static object
new (&staticObject) SimpleObject("John",23);
printf("In static object the name is %s\n",staticObject.name);
//Static memory
SimpleObject* staticMemoryObject = reinterpret_cast<SimpleObject*>(staticMemory);
new (staticMemoryObject) SimpleObject("Jenny",21);
printf("In static memory the name is %s\n",staticMemoryObject->name);
//Dynamic memory (heap)
void* dynamicMemoryObject = malloc( sizeof(SimpleObject) );
new (dynamicMemoryObject) SimpleObject("Xavier",22);
printf("In dynamic memory the name is %s\n",reinterpret_cast<SimpleObject*>(dynamicMemoryObject)->name);
free(dynamicMemoryObject);
//Dynamic object
SimpleObject* dynamicObject = new SimpleObject("Charles",31);
printf("In a dynamic object the name is %s\n",dynamicObject->name);
printf("Pointer of dynamic object is %8X\n",dynamicObject);
//Replacing a dynamic object with placement new
new (dynamicObject) SimpleObject("Charly",31);
printf("New name of dynamic object is %s\n",dynamicObject->name);
printf("Pointer of dynamic object is %8X\n",dynamicObject);
//Replacing a dynamic object with stack object
SimpleObject stackObject("Charl",31);
memcpy(dynamicObject,&stackObject,sizeof(SimpleObject));
printf("New name of dynamic object is %s\n",dynamicObject->name);
printf("Pointer of dynamic object is %8X\n",dynamicObject);
//Replacing a dynamic object with a new allocation
dynamicObject = new SimpleObject("Sandy",22);
printf("New name of dynamic object is %s\n",dynamicObject->name);
printf("Pointer of dynamic object is %8X\n",dynamicObject);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
随着输出:
在静态手动记忆中,名字是邪能21岁
在静态对象中,名称是John
在静态内存中,名称是Jenny
在动态内存中,名称是Xavier
在动态对象中,名称是Charles
动态对象的指针是4F8CF8
动态对象的新名称是Charly
动态对象的指针是4F8CF8
动态对象的新名称是Charl
动态对象的指针是4F8CF8
动态对象的新名称是Sandy
动态对象的指针是FD850
我认为你对指针与对象的概念有困难.
对象是某种类型的实例.无论是像int这样的基类型,还是像结构或类一样的用户定义类型.
使用newoperator,你可以在进程内存中创建一个这种类型的新实例,称为堆,就像一个里面有一堆衣服的房间.因此,如果你创建一件T恤的新实例,就好像你出去买了一件T恤并把它扔进了那堆.你知道你在某处有一件T恤的实例,但你真的不知道在哪里.
指针指向一个对象(通常).可以把它想象成一条连在你的T恤上的一根绳子,你就拥有另一根.这可以让你拉出你的T恤并用它做一些事情.可以将多件绳子连接到那件T恤上,不同的人可以抓住每件衣服,让每个人都能拉出来并使用它. 请记住,只有一件T恤,只有多个指针.
复制指针就像是将一段新的字符串附加到对象上.您可以通过将一个指针指向另一个来完成此操作tshirt* x = new tshirt(); tshirt* y = x;
虽然指针有点危险,因为它实际上不能指向任何东西.通常当程序员想要识别指针无效时,他们将其分配给NULL值,该值为0.在C++ 11中,nullptr应该使用而不是NULL出于类型安全的原因.
此外,如果delete在指针上使用运算符,则删除它指向的对象.您刚删除的指针和该指针的任何副本随后被称为悬空,这意味着它指向的内存位置实际上并不包含有效对象.作为程序员,您必须将这些指针的值设置为NULL/ nullptr或者您将很难跟踪代码中的错误.
可以使用std :: unique_ptr等智能指针缓解悬空指针问题(如果您浏览该链接,将鼠标悬停在"动态内存管理"上以获取更多指针包装器的信息).这些包装器试图阻止你无意中创建悬空指针和内存泄漏.
内存泄漏是指使用new运算符创建对象然后丢失指向它的指针.回到那堆衣服上,就像你丢下你的一条绳子,因此忘记你那里有T恤,所以你出去买另一件.如果你继续这样做,你会发现你的一堆衣服可能会填满整个房间并最终导致房间爆炸,因为你没有更多的空间可以容纳更多的T恤.
因此,要回到您的问题,要更改使用new运算符创建的对象的内容,可以使用间接运算符(*)取消引用该指针,或者可以调用成员函数或获取/设置成员函数的值使用结构解除引用运算符( - >)的对象.你是正确的,它object = new MyCustomObject()会给你一个新的指针地址,因为它已经创建了一个新的对象.如果你只想要指向同一个对象的新指针,你可以这样做:
MyCustomObject* pObject1 = new MyCustomObject();
// ... do some stuff ...
pObject1->doStuff();
(*pObject1).doMoreStuff();
pObject1->value = 3;
(*pObject1).value = 4;
// ... do some stuff ...
// This copies the pointer, which points at original object instance
MyCustomObject* pObject2 = pObject1;
// Anything done to object pointed at by pObject2 will be seen via going
// through pointer pObject1.
pObject2->value = 2;
assert(pObject1->value == 2); // asserting that pObject1->value == pObject2->value
Run Code Online (Sandbox Code Playgroud)
请注意,我将变量名称加上前缀p,I(和其他人)使用它来让我一眼就能确定变量是对象还是指向对象的指针.
可以在没有new关键字的函数调用堆栈上直接创建对象.
MyCustomObject object1; // Note: no empty parenthesis ().
MyCustomObject object2(1); // Only use parenthesis if you actually are passing parameters.
Run Code Online (Sandbox Code Playgroud)
当函数调用结束时(或在某些情况下更快),这些对象会自动销毁.
我认为这不是你想要的,但我刚刚添加它是为了完整性.
已经引用了placement new,它重用了已经分配的内存.这是一个有效但非常先进的功能.pObject1->~MyCustomObject()在执行新的(即)之前,您必须小心通过指针(即)调用析构函数,pObject1 = new (pObject1) MyCustomObject()否则您可能会有资源泄漏(文件或可能保持打开状态或其他资源可能未被清除).
祝好运.