When does this instantiation use memory?

Say I have a class which is the head of a linked list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
node
{
   public:

   node* NEXT;//does this use memory before it becomes NEXT_NODE or only after it?
   
   node(){}
   ~node(){}
};
//and then later I decide to create a node and pass it into node.
int main()
{
    node* NODE = new node();
    node* NEXT_NODE = new node();
    //does the declaration of NODE increase the memory usage only after this statement?
    NODE->NEXT = NEXT_NODE;
   
    return 0;
}



I guess the subsequent question would be (in case it does use memory before instantiation) is how would it be possible do this so that node* NEXT doesn't use memory before instantiation?
Last edited on
not quite sure what you mean, but...
when an object is instantiated, space for it's data members is allocated in the stack or heap (heap if you use the new keyword). node* NEXT would always take sizeof(void*) , usually 4 bytes. however, the data it is pointing to (either invalid pointer or another node object) can take up more space, but node* NEXT itself always takes the same size.
Ok, that makes sense so the total memory is 8 bytes used for the pointer and the object. Is there a way though to not use any memory for a pointer until the object of 4 bytes is assigned to it? If no, thats fine. Just seeing if theres some magical method I'm not familiar with.
Well, sort of. Just don't create the object until you have the data.
Ok what about the following code. It creates a type nodes with a type called another_node_type within it which is not used unless the counter is equal to zero? Heres the code. Is there a way to fix this problem?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>

class another_node_type
{
    private:

        int counter;

    public:

    another_node_type(){}
    ~another_node_type(){}
   another_node_type(int counter)
    {
        this->counter = counter;
        std::cout<<"another_node_type counter: "<<counter<<std::endl;
    }
};
class nodes
{
    private:

        nodes *object;
        another_node_type* another_object;

    public:

    nodes(){}
    ~nodes()
    {
        if(object)
            delete object;

        if(another_object)
            delete another_object;
    }
    nodes(int counter)
    {
        if(counter != 0)
        {
            counter--;
            std::cout<<"nodes counter: "<<counter<<" and another 4 bytes of another_node_type wasted?"<<std::endl;
            object = new nodes(counter);
        }
        else
        {
            another_object = new another_node_type(counter);
        }
    }
};
int main()
{
    nodes* NODES_OBJECT = new nodes(3);

    delete NODES_OBJECT;

    return 0;
}


this is the output

nodes counter: 2 and another 4 bytes of another_node_type wasted?
nodes counter: 1 and another 4 bytes of another_node_type wasted?
nodes counter: 0 and another 4 bytes of another_node_type wasted?
another_node_type counter: 0





Well, it's not wasted - or at least, it wouldn't be if you did something sensible with initialising it. It would be telling you whether or not there's an object of type another_node_type, and, if so, what the address of that object is.

I'm curious. What platform are you working on where memory is so restricted that it's worth wasting even a single second of your time worrying about the 4 bytes used to store a pointer?

EDIT: If this really is an issue, there are ways around it, but it's not worth compromising the robustness and maintainability of your code to do it unless you really need to.
Last edited on
Well, it's not wasted - or at least, it wouldn't be if you did something sensible with initialising it. It would be telling you whether or not there's an object of type another_node_type, and, if so, what the address of that object is.


Yeah but I don't need to know if the non-initialized another_node_types are null.

I'm curious. What platform are you working on where memory is so restricted that it's worth wasting even a single second of your time worrying about the 4 bytes used to store a pointer?


I guess its not that big of a deal but I want to make my code "perfect".

EDIT: If this really is an issue, there are ways around it, but it's not worth compromising the robustness and maintainability of your code to do it unless you really need to.


I'm curious what you have in mind. Please post any code possible. I'm interested just for the sake of knowing another method thats OOP and possible using virtuals and inheritance/polymorphism. If not thats fine.
Yeah but I don't need to know if the non-initialized another_node_types are null.

Really? If you ever actually use these objects, then at some point, presumably you're going to need some way of telling whether your node contains a nodes object or an another_node_type object. How is that going to be determined?

I guess its not that big of a deal but I want to make my code "perfect".

"Perfect" by what criteria? Robustness? Maintainability/readability? Optimal memory usage? Optimal performance? Conformance to some coding standard?

You can very rarely have all of these. If you try and make your code "perfect" with regard to one aspect, you usually wind up compromising it with regard to another. Personally, I would always value things like robustness and maintainability much higher than optimising memory usage - especially for something as paltry as storage for a single pointer.

I'm curious what you have in mind. Please post any code possible. I'm interested just for the sake of knowing another method thats OOP and possible using virtuals and inheritance/polymorphism.

Well, polymorphism was one thing I was thinking of. In fact, I think that would be a better design. Simply have nodes and another_node_type inherit from a common base class, and store a single pointer to that base class..

But, understand, this will come with it's own memory overhead. If you want polymorphism, you'll need virtual methods, which means that vtables will be created for your classes, using memory.

Nevertheless, it would be a much better design for your code, eliminating the need for two pointers.

The other thing I was thinking of was the messy, old-school C solution of using a void* pointer, to store the address of whichever type of object is created. But if you ever want to use that data, your code will need to know how to interpret it, which means storing that information somewhere in the object, which means - you guessed it - memory usage.
Last edited on
Well, polymorphism was one thing I was thinking of. In fact, I think that would be a better design. Simply have nodes and another_node_type inherit from a common base class, and store a single pointer to that base class..

But, understand, this will come with it's own memory overhead. If you want polymorphism, you'll need virtual methods, which means that vtables will be created for your classes, using memory.

Nevertheless, it would be a much better design for your code, eliminating the need for two pointers.

The other thing I was thinking of was the messy, old-school C solution of using a void* pointer, to store the address of whichever type of object is created. But if you ever want to use that data, your code will need to know how to interpret it, which means storing that information somewhere in the object, which means - you guessed it - memory usage.


Like I said I'd be grateful to see other methods for doing this, just for the sake of knowing it.However, I guess I will stick to my methods since you changed my mind. The void* pointer method does sound interesting. I've never used one for anything actually. Virtual tables however are runtime "hogs" in terms of speed or thats the rumor I've heard.
Like I said I'd be grateful to see other methods for doing this, just for the sake of knowing it.However, I guess I will stick to my methods since you changed my mind.

Well, actually, my recommendation was to use polymorphism, not stick to your current methods.

Virtual tables however are runtime "hogs" in terms of speed or thats the rumor I've heard.

Yes... if you're using a 1992 vintage computer, with a 1992 vintage compiler.

Seriously - do you honestly think Object-Oriented Programming would have become such a ubiquitous paradigm, and C++ such a dominant programming language, if virtual tables were "runtime hogs in terms of speed"?

Look... there are some situations where this might be an issue. Low-level OS or driver programming, perhaps. Or embedded software on low-performance devices.

But for the overwhelming majority of application development in C++, this stuff is fine. You're going to waste a lot of time - and end up with much less reliable software - if you avoid sensible, modern programming practices because you're worrying unnecessarily over stuff like this.
Last edited on
Well, actually, my recommendation was to use polymorphism, not stick to your current methods.

Could you show me an example please, thanks.
To expand on what I said a couple of posts ago, something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class nodeBase
{
public:
  nodeBase() {}
  virtual ~nodeBase() {}

  void setNextNode(nodeBase* anotherNode)
  {
    m_nextNode = anotherNode;
  }

  // Whatever interface methods you're going to need to actually do 
  // anything useful with this linked list.  For example:
  virtual void printNodeData() = 0; // Pure virtual - must be implemented in derived class

private:
  nodeBase* m_nextNode;
};

class normalNode : public nodeBase
{
public:
  // Constructor - use initialisation list
  normalNode(int data):
    m_intData(data) 
   {};
  virtual ~normalNode() {};

  virtual void printNodeData()
  {
    std::cout << "normalNodeData data is the integer " << m_intData << std::endl;
  }

private:

  // Data members
  int m_intData;
}

class anotherNodeType: public nodeBase
{
public:
  // Constructor - use initialisation list
  anotherNodeType(std::string data):
    m_stringData(data) 
   {};
  virtual ~anotherNodeType() {};

  virtual void printNodeData()
  {
    std::cout << "anotherNodeType data is the string" << m_stringData << std::endl;
  }

private:

  // Data members
  std::string m_stringData ;
}

int main()
{
  // Create a normal node as the head
  nodeBase* head = new normalNode(3);

  // Add another normal node
  nodeBase* secondNode = new normalNode(5);
  head->setNextNode(secondNode );

  // Add another type of node
  nodeBase* thirdNode = new anotherNodeType("Mary has a little lamb");
  secondNode->setNexNode(thirdNode);
  
}


Note, I just knocked this up in a few minutes as an example. I don't guarantee it's error-free, and it's certainly not a complete example of a linked list. It's just to illustrate the point. You should be able to adapt it to suit your purposes.
Last edited on
Well thanks MikeyBoy, you definitely get credit for the thread. I can fix the errors, I just needed a starting point thats all.

edit: I got this one compiled easily with placing semicolons

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>

class nodeBase
{
public:
  nodeBase() {}
  virtual ~nodeBase() {}

  void setNextNode(nodeBase* anotherNode)
  {
    m_nextNode = anotherNode;
  }

  // Whatever interface methods you're going to need to actually do
  // anything useful with this linked list.  For example:
  virtual void printNodeData() = 0; // Pure virtual - must be implemented in derived class

private:
  nodeBase* m_nextNode;
};

class normalNode : public nodeBase
{
public:
  // Constructor - use initialisation list
  normalNode(int data):
    m_intData(data)
   {};
  virtual ~normalNode() {};

  virtual void printNodeData()
  {
    std::cout << "normalNodeData data is the integer " << m_intData << std::endl;
  }

private:

  // Data members
  int m_intData;
};

class anotherNodeType: public nodeBase
{
public:
  // Constructor - use initialisation list
  anotherNodeType(std::string data):
    m_stringData(data)
   {};
  virtual ~anotherNodeType() {};

  virtual void printNodeData()
  {
    std::cout << "anotherNodeType data is the string" << m_stringData << std::endl;
  }

private:

  // Data members
  std::string m_stringData ;
};

int main()
{
  // Create a normal node as the head
  nodeBase* head = new normalNode(3);

  // Add another normal node
  nodeBase* secondNode = new normalNode(5);
  head->setNextNode(secondNode );

  // Add another type of node
  nodeBase* thirdNode = new anotherNodeType("Mary has a little lamb");
  secondNode->setNextNode(thirdNode);

}
Last edited on
Topic archived. No new replies allowed.