Array of objects vs. array of pointers

Pages: 12
Hello. Consider the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Object
{
public:
	int val;

	Object() : val(42) {}
	Object(const Object& o) : val(o.val) {}
	~Object() {}
};

int main()
{
	// Alternative 1
	Object* obs1 = new Object[2];

	// Alternative 2
	Object** obs2 = new Object*[2];
	obs2[0] = new Object;
	obs2[1] = new Object;
}


Do these two do the same thing? As far as I understand it, alternative one allocates memory for two Objects on the heap. Wouldn't the second alternative do the same thing, in that case?

I'm asking because I'm wondering whether using an array of Object* would be faster - whenever its size needs to be increased, assuming the space in memory right next to is is unavailable, everything would need to be recreated at another place in memory, right? If so, simply copying the addresses of the objects would be faster than just copying them altogether, I assume.

I'd appreciate any help on this matter.
Last edited on
Yes and no. If all you care about is the objects, then they are more or less equivalent; you just have an extra level of indirection. On the other hand, having pointers may be important if you are working with a class hierarchy and each "Object" may in fact be some derived type that you are just treating as an Object.

You may also want to note that the first allocates 2 objects on the heap, while the second allocates 2 pointers and 2 objects on the heap. A minor space difference in this case, but perhaps something to be aware of.
So, say I have the following class:

1
2
3
4
5
6
class LargeObject
{
public:
	double a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v;
	// ...
};


If I had an array of 100 LargeObjects, and I needed to regularly increase the size of it, which of the alternatives above would be better?

One reason why I'm asking is that I have some problems with the library SFML and its Music class:
1
2
3
4
5
6
7
8
// This can't load because the Music class is non-copyable
std::vector<sf::Music> m;
m.push_back(sf::Music());

// This loads without a problem
std::vector<sf::Music*> m;
sf::Music* mp = new sf::Music();
m.push_back(mp);
Last edited on
It depends. Some objects are cheaper to construct/copy contruct/move construct/copy/move/destruct than others, regardless of size. Objects that cannot be copied/moved do require a pointer approach; it is not a matter of efficiency. For the rest it is a balance between "simple and maintainable" vs. "the least CPU cycles ever".


You do use new and therefore you must use delete too. Not just use, but in right places too. Thus, you would rather use smart pointers or containers, rather than raw pointers.

Your alternative 1 should probably read:
std::vector<Object> obs1( 2 );
or perhaps
1
2
3
4
std::vector<Object> obs1;
obs1.reserve(2)
obs1.emplace_back();
obs1.emplace_back();

Likewise use of standard library for the alternative 2.
I think I get it.

On another note, what is the difference between creating a global variable and allocating memory using new or malloc for a variable of the same size?
I've read it, but I didn't find an answer as to which one is faster.
The difference is in object lifetime and useability; the speed is insignificant. You truly do not want to use global variables for anything without extremely good reason. There are two global variables that you probably have used, but let them be the only ones: std::cin & std::cout.
All right - if I go back to my original point, say I have an array of a hundred std::strings. Would it be faster to use vector<string> or vector<string*>?
Schulter wrote:
All right - if I go back to my original point, say I have an array of a hundred std::strings. Would it be faster to use vector<string> or vector<string*>?
There is not enough information to say one way or the other at this point in time.

Don't optimize early - it is best to optimize as late as possible. While you are writing code, always pick the simplest solution (the one that makes you write less code).
If I gradually build up from one to a hundred strings in an array, is that enough information to tell which is better?
Do you mean something like:
1
2
3
4
5
6
7
std::vector<std::string> obs1;
obs1.reserve( 100 );

std::string word;
while ( obs1.size() < 100 && std::cin >> word ) {
  obs1.push_back( word );
}

It may look like alternative 1, but might actually be more like alternative 2. Do you know why?
I'm not very familiar with std::vector. No, I don't know why, but that's not what I meant, either.

1
2
3
4
5
6
void AppendStrings(uint amount)
{
  std::vector<std::string> arr;
  for (uint i = 0; i < amount; i++)
  { arr.push_back("Hello!"); }
}


Something like the above, except the amount is not known at compile-time.
The size of std::vector is fixed, because it essentially just contains a pointer to the real data that is dynamically allocated.
http://info.prelert.com/blog/stl-container-memory-usage
Similarly, the std::string usually has a pointer to the actual dynamically allocated char array.
1
2
std::vector<std::string> obs1;
char * * obs2;

Effectively, obs1 and obs2 are almost identical, but obs1 is massively simpler to use.


Your example doesn't really differ from mine, except in details. My code calls vector::reserve(), so there is memory allocated for all 100 strings in one step without constructing empty strings.

Your code can be rewritten with fill-type constructor:
1
2
3
4
void AppendStrings(uint amount)
{
  std::vector<std::string> arr( amount, "Hello!" );
}

That creates and initializes all amount strings in one step.
That's not my point - perhaps using String was a bad idea.

1
2
3
4
5
6
7
8
9
10
11
class Object
{
public:
  double a, b, c, d, e, f, g, h, i, j;
};

int main()
{
  std::vector<Object> v1;
  std::vector<Object*> v2;
}


Now, is it faster to dynamically fill v1 or v2 with, say, two hundred Objects?
Last edited on
If speed of insertion and removal is your concern, use a different container. But you should not resort to using pointers.

To answer your bad question: it would be faster to fill v2 because vector is the wrong container to use for this purpose. Though, if you were also dynamically allocating each object for v2, then v1 would be faster. It depends. You cannot make a decision about optimization until you have all information. This is why your question is bad: there is no way to know which answer is correct with the information you have provided.

By the way, if your solution involves pointers, you're probably doing it wrong.
http://www.LB-Stuff.com/pointers
Last edited on
By a different container, are you talking about a list? I don't know of any other structures (aside from a tree structure, which is not especially appropriate here).

(I'm aware that my code is probably not modern relative to newer C++ standards. I generally use C++ as "C with classes and generic types".)
C++ has several container types defined for you in the standard library:
http://www.cplusplus.com/reference/stl/
http://en.cppreference.com/w/cpp/container
Yes, I've read it, but as far as I understand, the only data structures that are appropriate for this is vector, list and deque, and a list is not that good for direct access.
How do you know? You have not even explained how you intend to use your container. Will you spend more time looping through it than adding elements to it? Will it need to have elements added and removed frequently? Can it contain duplicates? Does it need to stay sorted? Any other important details?

You do not have enough information to make an informed decision about which container to use, so your question is unanswerable.
Last edited on
Pages: 12