16
MyCustomObject * object=new MyCustomObject();

Assume the object pointer is used by many of my classes, but all of a sudden I want to change the contents of the pointer without changing the address.

Am I wrong in thinking that object = new MyCustomObject() will give a new pointer address to the object? I want the new object without changing the pointer address (Yes, I will make sure to clean the old object).

Michael0x2a
  • 58,192
  • 30
  • 175
  • 224
Jeremie D
  • 4,145
  • 1
  • 35
  • 41
  • 3
    Without seeing code specific specific advise is hard but sounds like you need some methods on `MyCustomObject` to set or reset the contents. – Shafik Yaghmour Jun 05 '13 at 16:50
  • Maybe use a [smart pointer](http://en.cppreference.com/w/cpp/memory)? – Some programmer dude Jun 05 '13 at 16:51
  • yes, the second `new` will allocate fresh memory (if default new is used). re-using the same memory block would take some lines including building the new data, copying the data over the old data. this should only be done on objects of the same absolute size, or you will run into access violations / segmentation faults. – scones Jun 05 '13 at 16:52
  • The concepts of "pointer" and "address" are synonymous in C++ (aside from possible semi-formal rvalue vs. lvalue distinction). The request to "change the pointer without changing the address" is not exactly clear to me. You have to explain better what you are trying to do. – AnT stands with Russia Jun 05 '13 at 16:52
  • Also, what does "pointer is used by many of my classes" mean? How do these "many classes" gain access to the same pointer? – AnT stands with Russia Jun 05 '13 at 16:55
  • 2
    You don't mean "change the contents of the pointer". You mean "change the thing to which the pointer points" or, really, "replace it with a new object". You're right in thinking that you'd basically have to update _every_ pointer that you had to the old object, to now point to the new, replacement object... unless you can overwrite it in place, or otherwise manipulate the state of the _existing_ object to achieve the same goal. – Lightness Races in Orbit Jun 05 '13 at 16:56
  • So you want to overwrite the object at the same memory address? – Boyko Perfanov Jun 05 '13 at 16:56
  • 4
    I don't fully understand the quesiton, but [placement new](http://en.wikipedia.org/wiki/Placement_syntax) could be something to look at. – juanchopanza Jun 05 '13 at 16:59
  • Also, this is one good reason not to store pointers. – Lightness Races in Orbit Jun 05 '13 at 17:21
  • The content of a pointer is an address. If you "change the contents of the pointer", then by definition you are changing the address to which it points. Of course you can change the contents of the object to which it points without changing its address: `int* p = new int(42); *p = 43;`. I suspect that's what you meant, but it's not what you asked. – Keith Thompson Jun 05 '13 at 17:33
  • If you'd provide an interface function like `clear()` or whatever for your object, you don't have to fiddle around with placement new and stuff. – Pixelchemist Jun 05 '13 at 18:57

6 Answers6

14

Generally it is preferable to change an object’s properties (by calling its methods) rather than deleting it and creating a new one. In particular, you can completely replace the object by assignment, such as:

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

Instead of the default constructor, you could use an existing instance of the object (e.g., some static object you define for this purpose) or the result of a function that returns the desired object.

However, you can delete an object but retain its space by calling its destructor, and you can create a new object in the same place by using 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;
}

After calling the destructor and the placement new, pointers to the old object point to the new object, since it is in the same place the old object was.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 7
    Note that this can be _extremely_ dangerous if the constructor could throw an exception. `*object=MyCustomObject();` _might_ (or might not) be more what the OP needs. – Mooing Duck Jun 05 '13 at 17:54
  • if the destructor has an empty function body, is it still nescessary to call it?... when commenting out the destructor call it still works for me – Juarrow Jun 05 '13 at 19:57
  • @Incubbus: The members and base class of the object must still be destroyed, so the destructor should be called. It is good practice to call the destructor anyway, in case it becomes non-empty in the future. If the class has a trivial destructor, it can be defined in the class declaration, so the definition is visible to users of the class, and the compiler can optimize away calls. – Eric Postpischil Jun 05 '13 at 19:59
  • If the constructor throws an exception, there's a memory leak (because there's no catch for the exception which releases the memory — which has of course to be done with with `operator delete` in that case, not with `delete`), but other than that I can't see any negative effect. The true danger comes when explicitly calling the destructor on automatic objects, or on objects whose lifetime is managed by other code (e.g. smart pointers). Or when the new object is not of the same dynamic type as the original one (so the allocated memory might not be large enough). – celtschk Jun 05 '13 at 23:23
10

Objects in Memory

This is a matter of understand how memory works for objects in C++

Lets imagine we have the following object:

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

It's size will be 20. (In most platforms). So in memory it will look like this:

Bytes
name             age
0000000000000000|0000|

You can change memory manually so you could create the object by doing something like:

//Manual assigment
staticMemory[0] = 'F';
staticMemory[1] = 'e';
staticMemory[2] = 'l';
staticMemory[3] = 0;

int* age = reinterpret_cast<int*>(&staticMemory[16]);
*age = 21;

You can prove object is successfully created by doing something like:

printf("In static manual memory the name is %s %d years old\n",
     reinterpret_cast<SimpleObject*>(staticMemory)->name
     ,reinterpret_cast<SimpleObject*>(staticMemory)->age);

Which outputs:

In static manual memory the name is Fel 21 years old

By obvious practical reasons this is not used in real life, but it helps understand how objects are storage.

New operator

New operator basically works as this:

  1. Allocate the size of the object in bytes in the heap memory
  2. Call the object constructor to fill the memory

It's more complicated depending on the implementation, but the idea is the same.

So if the constructor is:

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

This code:

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

Will be almost equivalent to:

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

As I said is a little bit more complicated than that, but the idea is the same.

Replacing an object in memory

Now that this is understood there are many ways to replace an object in the same memory space, the most common way is placement new. Many examples below:

#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;
}

With output:

In static manual memory the name is Fel 21 years old

In static object the name is John

In static memory the name is Jenny

In dynamic memory the name is Xavier

In a dynamic object the name is Charles

Pointer of dynamic object is 4F8CF8

New name of dynamic object is Charly

Pointer of dynamic object is 4F8CF8

New name of dynamic object is Charl

Pointer of dynamic object is 4F8CF8

New name of dynamic object is Sandy

Pointer of dynamic object is FD850

Community
  • 1
  • 1
felknight
  • 1,383
  • 1
  • 9
  • 25
6

I think you are having difficulty with the concepts of pointer vs object.

An object is an instance of some type. Be it a base type like an int or a user defined type like a struct or class.

Using new operator, you create a new instance of this type inside of the process's memory called the heap, which is like a room with a pile of clothes in it. So if you create a new instance of a t-shirt, it is like you went out and bought a t-shirt and threw it into that pile. You know that you have an instance of a t-shirt in there somewhere, but you don't really know where.

A pointer points to an object (usually). Think of it like a piece of string that is attached to your t-shirt on one end and you have the other. This allows you to pull out your t-shirt and do stuff with it. Multiple pieces of string can be attached to that t-shirt with different people holding on to each piece, allowing each person to pull it out and use it. Remember, there is only one t-shirt, just multiple pointers to it.

Copying a pointer is like having a new piece of string attaching itself to the object. You do this by assigning one pointer to another tshirt* x = new tshirt(); tshirt* y = x;

A pointer though is a bit dangerous, because it can actually not point to anything. Usually when a programmer wants to recognise that a pointer is not valid, they assign it to NULL, which is a value of 0. In C++11, nullptr should be used instead of NULL for type safety reasons.

Further, if you use the delete operator on a pointer, you are deleting the object it is pointing at. The pointer you just deleted through and any copy of that pointer is then said to be dangling, which means that it is pointing at a memory location that doesn't actually contain a valid object. As a programmer, you must set the value of these pointers to NULL/nullptr or you will have difficult to track down bugs in your code.

The dangling pointer problem can be mitigated using smart pointers like std::unique_ptr and others (if you go through that link, hover over "Dynamic memory management" to get info on more pointer wrappers). These wrappers try and stop you inadvertently creating dangling pointers and memory leaks.

A memory leak is when you create an object using the new operator and then lose the pointer to it. Going back to the pile of clothes analogy, it would be like you dropped your piece of string and thus forgot that you have t-shirt in there, so you go out and buy another one. If you keep doing this, you will find that your pile of clothes may fill the room and eventually cause the room to explode as you have no more room for more t-shirts.

So to get back to your question, to change the contents of an object that you created using the new operator, you can dereference that pointer using the indirection operator (*) or you can call a member function or get/set a member value of the object using the structure dereference operator (->). You are correct that the object = new MyCustomObject() will give you a new pointer address because it has created a new object. If you just want to new pointer that points at the same object, you would do something like this:

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

Note that I prefixed the variable name with p, I (and others) use this to allow me at a glance to determine if the variable is an object or a pointer to an object.

Objects can be created directly on the function call stack without the new keyword.

MyCustomObject object1;    // Note: no empty parenthesis ().
MyCustomObject object2(1); // Only use parenthesis if you actually are passing parameters.

These objects are automatically destroyed when the function call ends (or in some cases sooner).

Advanced

I'm thinking that this is not really what you wanted, but I have just added it for completeness.

There have been references to placement new, which reuses memory that has already been allocated. This is a valid but quite an advanced feature. You have to be careful to call the destructor through the pointer (i.e. pObject1->~MyCustomObject()) prior to doing the in place new (i.e. pObject1 = new (pObject1) MyCustomObject()) otherwise you can have a resource leak (files or may be left open or other resources may be not cleaned up).

Good luck.

Adrian
  • 10,246
  • 4
  • 44
  • 110
  • 1
    +1 for the pile of clothes analogy, that is a great way to teach pointers/objects and memory management. – Luke B. Jun 05 '13 at 18:55
-3

The pointer IS the object, so if you do new Object() you create a new one, but the functions with the prevoius pointer will not see it. If you want to change the content, you can do this, because all other objects which know the pointer will reference the values that your object contains. It's a bit similar to a global variable. So you can pass around the pointer and all functions will see your changes as soon as they acces the object.

Devolus
  • 21,661
  • 13
  • 66
  • 113
  • 5
    "The pointer IS the object", what does that mean? The pointer is the pointer (which can be considered an object, but you probably mean something else). – juanchopanza Jun 05 '13 at 17:03
  • 2
    This answer appears to be constructed primarily of nonsense. – Lightness Races in Orbit Jun 05 '13 at 17:14
  • 1
    I sorta see what @Devolus is attempting to say, but it is unclear and confusing. – Adrian Jun 05 '13 at 18:02
  • @LightnessRacesinOrbit, maybe you should read more carefully. Care to elaborate where the "nonsense" is? – Devolus Jun 06 '13 at 05:18
  • @Devolus: "The pointer IS the object" "The functions with the prevuois pointer" (those functions cannot possible be in scope any more, unless the OP is using a wait loop in a worker thread that he's not mentioned) "It's a bit similar to a global variable" – Lightness Races in Orbit Jun 06 '13 at 08:56
  • The problem is that, although what you're _trying_ to say is correct, you've gone a little too far with your analogies and said things that are not true, and would mislead the OP into falsehoods. I don't say this to be mean, but only to objectively review your answer! – Lightness Races in Orbit Jun 06 '13 at 08:57
  • @LightnessRacesinOrbit, regarding how the poster set up his code, the pointer is distributed in many classes, so changing the pointer doesn't help, because the pointer represents the object, and in this regard acts similar to a global variable (an unknown number of objects have access to the existing pointer). So allocating a new object doesn't help, otherwise you would have to update all the classes (which the poster doesn't seem to want or cant), holding the previous copy of the pointer, with the new one. – Devolus Jun 06 '13 at 09:00
  • @Devolus: Yes, I understand that. As I said already, you're not _wrong_, you're just saying it all in a borderline nonsense fashion. ;) – Lightness Races in Orbit Jun 06 '13 at 09:09
-3

Everytime you create a new object via the new operator the system looks for a good address for it on the heap. You cannot instruct it to give you a certain address, even if you know it's free and usable.

The only thing you can do is change properties of the object at a certain address, like the number stored in an int variable.

You're right, the operator new returns a new address, or let's say the address the system decided.

blue
  • 2,683
  • 19
  • 29
-3

Implement allocator to return same address, and use it in new and delete operator overloaded.

kobake
  • 1,091
  • 1
  • 12
  • 15