C ++指针:更改内容而不更改地址?

时间:2013-06-05 16:48:21

标签: c++ pointers

MyCustomObject * object=new MyCustomObject();

假设我的许多类都使用了对象指针,但突然间我想改变指针的内容而不改变地址。

我认为object = new MyCustomObject()会给对象一个新的指针地址是错误的吗?我想要新对象而不更改指针地址(是的,我将确保清理旧对象)。

6 个答案:

答案 0 :(得分:13)

通常,最好更改对象的属性(通过调用其方法),而不是删除它并创建一个新属性。特别是,您可以通过赋值完全替换对象,例如:

*object = MyCustomObject(); // Replace object with the result of default constructor.

您可以使用对象的现有实例(例如,为此目的定义的某个静态对象)或返回所需对象的函数的结果,而不是默认构造函数。

但是,您可以通过调用其析构函数来删除对象但保留其空间,并且可以使用展示位置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;
}

在调用析构函数和放置new之后,指向旧对象的指针指向新对象,因为它与旧对象位于同一位置。

答案 1 :(得分:6)

内存中的对象

这是理解C ++中对象的内存如何工作的问题

假设我们有以下对象:

class SimpleObject
{
public:
    char name[16];
    int age;
};

它的大小将是20.(在大多数平台上)。所以在内存中它看起来像这样:

Bytes
name             age
0000000000000000|0000|

您可以手动更改内存,以便通过执行以下操作来创建对象:

//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);

哪个输出:

  

在静态手动记忆中,名字是邪能21岁

由于显而易见的实际原因,这在现实生活中并未使用,但它有助于了解对象的存储方式。

新操作员

新操作符基本上可以这样工作:

  1. 在堆内存中以字节为单位分配对象的大小
  2. 调用对象构造函数以填充内存
  3. 取决于实现,它更复杂,但想法是一样的。

    所以如果构造函数是:

    SimpleObject::SimpleObject(const char* name,int age)
    {
        memcpy(this->name,name,16);
        this->age = age;
    }
    

    此代码:

    SimpleObject* dynamicObject = new SimpleObject("Charles",31);
    

    几乎相当于:

    SimpleObject* dynamicMemoryObject = (SimpleObject*)malloc( sizeof(SimpleObject) );
    memcpy(dynamicMemoryObject->name,"Charles",16);
    dynamicMemoryObject->age = 31;    
    

    正如我所说的那样复杂一点,但想法是一样的。

    更换内存中的对象

    现在可以理解,有很多方法可以替换同一内存空间中的对象,最常见的方法是放置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;
    }
    

    输出:

      

    在静态手动记忆中,名字是邪能21岁

         

    在静态对象中,名称为John

         

    在静态内存中名称为Jenny

         

    在动态内存中,名称为Xavier

         

    在动态对象中,名称为Charles

         

    动态对象的指针是4F8CF8

         

    动态对象的新名称是Charly

         

    动态对象的指针是4F8CF8

         

    动态对象的新名称是Charl

         

    动态对象的指针是4F8CF8

         

    动态对象的新名称是Sandy

         

    动态对象的指针是FD850

答案 2 :(得分:6)

我认为你对指针与对象的概念有困难。

对象是某种类型的实例。无论是像int这样的基类型,还是像结构或类一样的用户定义类型。

使用new运算符,在进程的内存中创建一个这种类型的新实例,称为堆,就像一个里面有一堆衣服的房间。因此,如果你创建一件T恤的新实例,就好像你出去买了一件T恤并把它扔进了那堆。你知道你在某处有一件T恤的例子,但你真的不知道在哪里。

指向对象的指针(通常)。可以把它想象成一条连在你的T恤上的一根绳子,你就拥有另一根。这可以让你拉出你的T恤并用它做一些事情。可以将多件绳子连接到那件T恤上,不同的人可以抓住每件衣服,让每个人都能拉出来并使用它。 记住,只有一件T恤,只有多个指针。

复制指针就像将一个新的字符串附加到对象上一样。您可以通过将一个指针指向另一个tshirt* x = new tshirt(); tshirt* y = x;

来完成此操作

虽然指针有点危险,因为它实际上并不指向任何东西。通常当程序员想要识别指针无效时,他们会将其分配给NULL,其值为0.在C ++ 11中,应使用nullptr而不是{{1}出于类型安全的原因。

此外,如果在指针上使用NULL运算符,则删除它指向的对象。您刚删除的指针和该指针的任何副本随后被称为悬空,这意味着它指向的内存位置实际上并不包含有效对象。作为程序员,您必须将这些指针的值设置为delete / NULL,否则您很难找到代码中的错误。

可以使用std::unique_ptr等智能指针缓解悬空指针问题(如果您浏览该链接,将鼠标悬停在“动态内存管理”上以获取更多指针包装器的信息)。这些包装器试图阻止你无意中创建悬空指针和内存泄漏。

内存泄漏是指使用nullptr运算符创建对象然后丢失指向它的指针。回到那堆衣服上,就像你丢下你的一条绳子,因而忘记你那里有T恤,所以你出去买另一件。如果你继续这样做,你会发现你的一堆衣服可能会填满整个房间并最终导致房间爆炸,因为你没有更多空间可以容纳更多的T恤。

因此,要回到您的问题,要更改使用new运算符创建的对象的内容,可以使用间接运算符(*)取消引用该指针,也可以调用成员函数或使用结构解除引用运算符( - &gt;)获取/设置对象的成员值。你是正确的new会给你一个新的指针地址,因为它创建了一个新对象。如果你只想要指向同一个对象的新指针,你可以这样做:

object = new MyCustomObject()

请注意,我使用p为变量名前缀,I(和其他人)使用它来让我一眼就能确定变量是对象还是指向对象的指针。

可以直接在函数调用堆栈上创建对象,而不使用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 关键字。

new

当函数调用结束时(或在某些情况下更快),会自动销毁这些对象。

高级

我认为这不是你想要的,但我刚刚添加它是为了完整。

已经引用了placement new,它重用了已经分配的内存。这是一个有效但非常先进的功能。在执行new(即MyCustomObject object1; // Note: no empty parenthesis (). MyCustomObject object2(1); // Only use parenthesis if you actually are passing parameters. )之前,必须小心通过指针调用析构函数(即pObject1->~MyCustomObject()),否则可能会导致资源泄漏(文件或可能保持打开状态或其他资源可能没有清理干净。)

祝你好运。

答案 3 :(得分:-3)

指针是对象,所以如果你new Object()创建一个新指针,但带有prevoius指针的函数将看不到它。如果要更改内容,可以执行此操作,因为知道指针的所有其他对象将引用对象包含的值。它有点类似于全局变量。因此,您可以传递指针,所有函数一旦访问对象就会看到您的更改。

答案 4 :(得分:-3)

每次通过new运算符创建新对象时,系统都会在堆上查找它的好地址。你不能指示它给你一个特定的地址,即使你知道它是免费的和可用的。

您唯一能做的就是更改某个地址对象的属性,例如存储在int变量中的数字。

你没错,运营商new会返回一个新地址,或者说系统决定的地址。

答案 5 :(得分:-3)

实现allocator以返回相同的地址,并在new和delete operator中使用它。