Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Allocate Memory Without Activating Constructors

I'm reading in values from a file which I will store in memory as I read them in. I've read on here that the correct way to handle memory location in C++ is to always use new/delete, but if I do:

DataType* foo = new DataType[sizeof(DataType) * numDataTypes];

Then that's going to call the default constructor for each instance created, and I don't want that. I was going to do this:

DataType* foo;
char* tempBuffer=new char[sizeof(DataType) * numDataTypes];
foo=(DataType*) tempBuffer;

But I figured that would be something poo-poo'd for some kind of type-unsafeness. So what should I do?

And in researching for this question now I've seen that some people are saying arrays are bad and vectors are good. I was trying to use arrays more because I thought I was being a bad boy by filling my programs with (what I thought were) slower vectors. What should I be using???

like image 680
schnozzinkobenstein Avatar asked Jan 01 '11 23:01

schnozzinkobenstein


People also ask

Can we dynamically allocate memory without pointers?

No, the two arrays are completely independent objects, that have nothing to do with each other, whatsoever.

Does default constructor allocate memory?

A constructor does not allocate memory for the class object its this pointer refers to, but may allocate storage for more objects than its class object refers to. If memory allocation is required for objects, constructors can explicitly call the new operator.

How does C allocate memory?

In C, dynamic memory is allocated from the heap using some standard library functions. The two key dynamic memory functions are malloc() and free(). The malloc() function takes a single parameter, which is the size of the requested memory area in bytes. It returns a pointer to the allocated memory.

Do you have to allocate memory in C?

Dynamic allocation is required when you don't know the worst case requirements for memory. Then, it is impossible to statically allocate the necessary memory, because you don't know how much you will need. Even if you know the worst case requirements, it may still be desirable to use dynamic memory allocation.


7 Answers

Use vectors!!! Since you know the number of elements, make sure that you reserve the memory first (by calling myVector.reserve(numObjects) before you then insert the elements.).

By doing this, you will not call the default constructors of your class.

So use

std::vector<DataType> myVector; // does not reserve anything
...
myVector.reserve(numObjects); // tells vector to reserve memory
like image 53
villintehaspam Avatar answered Oct 05 '22 13:10

villintehaspam


You can use ::operator new to allocate an arbitrarily sized hunk of memory.

DataType* foo = static_cast<DataType*>(::operator new(sizeof(DataType) * numDataTypes));

The main advantage of using ::operator new over malloc here is that it throws on failure and will integrate with any new_handlers etc. You'll need to clean up the memory with ::operator delete

::operator delete(foo);

Regular new Something will of course invoke the constructor, that's the point of new after all.

It is one thing to avoid extra constructions (e.g. default constructor) or to defer them for performance reasons, it is another to skip any constructor altogether. I get the impression you have code like

DataType dt;
read(fd, &dt, sizeof(dt));

If you're doing that, you're already throwing type safety out the window anyway.

Why are you trying to accomplish by not invoking the constructor?

like image 37
Logan Capaldo Avatar answered Oct 05 '22 15:10

Logan Capaldo


You can allocate memory with new char[], call the constructor you want for each element in the array, and then everything will be type-safe. Read What are uses of the C++ construct "placement new"?

That's how std::vector works underneath, since it allocates a little extra memory for efficiency, but doesn't construct any objects in the extra memory until they're actually needed.

like image 36
Ben Voigt Avatar answered Oct 05 '22 13:10

Ben Voigt


You should be using a vector. It will allow you to construct its contents one-by-one (via push_back or the like), which sounds like what you're wanting to do.

like image 37
Chris Jester-Young Avatar answered Oct 05 '22 15:10

Chris Jester-Young


I think you shouldn't care about efficiency using vector if you will not insert new elements anywhere but at the end of the vector (since elements of vector are stored in a contiguous memory block).

like image 24
Vladimir Avatar answered Oct 05 '22 14:10

Vladimir


vector<DataType> dataTypeVec(numDataTypes);

And as you've been told, your first line there contains a bug (no need to multiply by sizeof).

like image 34
hillel Avatar answered Oct 05 '22 14:10

hillel


Building on what others have said, if you ran this program while piping in a text file of integers that would fill the data field of the below class, like:

./allocate < ints.txt

Then you can do:

#include <vector>
#include <iostream>

using namespace std;

class MyDataType {
public:
  int dataField;
};


int main() {

  const int TO_RESERVE = 10;

  vector<MyDataType> everything;
  everything.reserve( TO_RESERVE );

  MyDataType temp;
  while( cin >> temp.dataField ) {
    everything.push_back( temp );
  }

  for( unsigned i = 0; i < everything.size(); i++ ) {
    cout << everything[i].dataField;
    if( i < everything.size() - 1 ) {
      cout << ", ";
    }
  }
}

Which, for me with a list of 4 integers, gives:

5, 6, 2, 6
like image 30
Michael Rivera Avatar answered Oct 05 '22 14:10

Michael Rivera