I'm working with a dynamic array of a given class, let's call it 'MyClass', the thing is this class has a specialized constructor with a given parameter.
As far as I know to initialize a dynamic array I should use this:
MyClass *myArray = new MyClass[]();
Is there a way to initialize my array using my specialized constructor? something like:
MyClass *myArray = new MyClass[](givenParameter);
and this got me to another question, what does the line MyClass *myArray = new MyClass[](); is it calling a base constructor without any given parameters or does it do something else internally?
It may be something obvious but I wasn't able to find much information on this, at least not something to solve my first question. Thank you, everyone.
The syntax MyClass *myArray = new MyClass[size](); allows you to value-initialize the elements when they are trivial simple types (like integers, etc, thus setting them to 0), but it is not very meaningful for elements of class/struct types, so the () is usually omitted for those types. new[] can only call default constructors on class/struct types, it does not allow you to call non-default constructors.
However, a way to handle that is to use placement-new instead, which would then allow you to construct each MyClass object individually, even with different parameter values if needed.
// allocate raw memory to hold the objects array...
char *myArrayBuf = new char[sizeof(MyClass) * NumberOfItems];
/* alternatively, in C++11 and later:
#include <type_traits>
using element_type = std::aligned_storage<sizeof(MyClass), alignof(MyClass)>::type;
element_type *myArrayBuf = new element_type[NumberOfItems];
*/
// call the constructor on each object in the array...
MyClass *myArray = reinterpret_cast<MyClass*>(myArrayBuf);
for(int i = 0; i < NumberOfItems; ++i) {
new(&myArray[i]) MyClass(givenParameter);
}
// use myArray as needed ...
// call the destructor on each object in the array...
for(int i = 0; i < NumberOfItems; ++i) {
myArray[i].~MyClass();
}
// deallocate the raw memory for the array...
delete[] myArrayBuf;
In C++11 and later, this would be easier to handle using a std::vector instead (which you should be using anyway):
#include <vector>
std::vector<MyClass> myArray;
myArray.reserve(NumberOfItems);
for(int i = 0; i < NumberOfItems; ++i) {
myArray.emplace_back(givenParameter);
}
// use myArray as needed ...
Prior to C++11, you can still use std::vector, but it would require copy-constructing the array elements:
#include <vector>
std::vector<MyClass> myArray;
myArray.reserve(NumberOfItems);
for(int i = 0; i < NumberOfItems; ++i) {
myArray.push_back(MyClass(givenParameter));
}
// use myArray as needed ...
MyClass *arr;
arr = new MyClass[2]{{10, "hello"},{20, "custom constructor"}};
I'm not sure there's another way to initialize C-array with non-standard constructor.
But if you're ok with using std::vector then:
#include <vector>
size_t size = 2;
std::vector<MyClass> myArray(size, MyClass(givenParameter));
Related
I was wondering if it was possible to create an array of objects when the object needs things passed into it for the constructor. I want something like this:
MyClass *myVar;
myVar = new MyClass[num]; // I would like to specify the array size after declaration
int i = 0;
for(i = 0;i < num;i++)
myVar[i] = new MyClass(0,0); // I would also like to populate the array with new objects
I know that this works:
MyClass *myVar;
myVar = new MyClass[num];
but this only works when the constructor has nothing passed into it. Is what I am trying to do possible? If so, how do I do it?
EDIT: I found out how to do it with using arrays. Here is how I did it:
MyClass **myVar;
myVar = new MyClass *[num];
for(i = 0;i < num;i++)
myVar[0] = new MyClass(0,0);
I would use vectors and such but my teacher has told us to use basic arrays whenever possible. The above solution I actually got from some code my teacher wrote. Thank you all for your help!
MyClass *myVar;
myVar = new MyClass[num];
Actually in this form you cannot invoke constructor which takes parameter(s). It is not allowed by the language specification.
However, if you use std::vector, which I recommend you to use, then you can create a vector calling non-default constructor as:
#include <vector> //header file where std::vector is defined
std::vector<MyClass> arr(num, MyClass(10,20));
It creates a vector of num elements, each element is created by calling copy-constructor of the class, passing MyClass(10,20) as argument to it.
The vector is also good because now you dont need to manage memory yourself. Neither manual allocation, nor manual deallocation. Plus, you can know the number of elements by calling arr.size() anytime. You always know how many elements the vector contains. You can also add elements anytime, just by calling .push_back() member function as:
arr.push_back(MyClass(20,30));
And now you can access elements, just like you access array, i.e by using index:
f(arr[i]); // 0 <= i < arr.size();
Additionally, you can use iterators which facilitate idiomatic programming, enabling you to use various algorithmic functions from <algorithm> header as:
#include <algorithm> //header file where std::for_each is defined
std::for_each(arr.begin(), arr.end(), f);
where f is function which takes one argument of type MyClass& (or MyClass const &) depending on what you want to do in f.
In C++11, you can use lambda as:
std::for_each(arr.begin(), arr.end(), [](const MyClass & m)
{
//working with m
});
In C++0x, this grammar works, which can call the non-default constructor in new expression:
MyClass *myVar;
myVar = new MyClass[2]{{10, 20},{20, 30}};
But I doubt if it works when the number of elements in available only at run time.
The vector approach would be better, as shown in Nawaz's answer.
Pointer to pointer is equivalent to 1. array of pointers, and 2. vector<T*> vector of pointers. One way I've done this in the past is using a double pointer. This approach eliminates the overhead of vector data structure and preferred memory efficient is needed.
MyClass ** myvar;
myvar = new Myclass*[num]
for(int i = 0; i < num; i++){
*(myvar+i) = new Myclass(i);}
Works with pretty much any control structure you can imagine. The drawback is that the allocation of memory is not contiguous and my affect speed for large number of num.
You can do something like this too:
MyClass *myVar[num];
for(int i = 0; i < num; i += 1)
{
myVar[i] = new MyClass(0, 0);
}
Actually, you can use a placement new to handle this:
MyClass * myVar;
myVar = reinterpret_cast<MyClass *>(new char[num * sizeof(MyClass)]);
int i = 0;
for (i = 0; i < num; i++) {
new(&myVar[i]) MyClass(0,0);
}
#Nawaz answer is really good about using vectors, but didn't work for me because it create vector of the same objects (all of them reference to the same object)
class Graph
{
public:
Graph(long V); // none default Constructor
}
std::vector<Graph> myGraph;
for (int i = 0; i < T; i++) // read all graphs
{
Graph newGraph(N);
myGraph.push_back(newGraph);
}
I am trying to make void* to hold a value (to avoid default constructor calling).
I want to:-
copy K to void* e.g. K k1; --> void* raw=k1;
copy void* to K e.g. void* raw; --> K k2=raw;
try not to break destructor and causes memory leak
don't use any dynamic allocation (heap, performance reason)
Here is what I tried:-
class K{
public: std::string yes="yes" ;
};
int main() {
//objective: k1->raw->k2 , then delete "raw"
void* raw[sizeof(K)]; //<--- try to avoid heap allocation
K k1;
static_cast<K>( raw)=k1; //<--- compile fail
K k2= static_cast<K>( raw);
std::cout<<k2.yes; //test
static_cast<K&>(raw)::~K(); //mimic destructor
return 0;
}
Question: Please provide a valid code that demonstrate a correct way to do this.
I found how to use placement new (https://stackoverflow.com/a/4756306/3577745 ), but not found how to use void* for a variable that is not an array.
C++ is new for me.
Edit :
I am writing a very custom collection (array).
Each element is encapsulated in a custom structure KCap kcap(with hold only 1 element, i.e. K).
Thus, I have to declare K k as a field of the encapsulator KCap.
However, I want to avoid default constructor of K, so I think void* can solve my issue.
What you are trying to do doesn't make sense. A void * is used to hold an arbitrary type of pointer, not an arbitrary type of other object. If you want to use storage for an arbitrary object type, use a char[].
Other problems with your code include that you need to ensure correct alignment of the raw storage, use reinterpret_cast to a reference rather than static_cast to a non-reference, your in-place destructor call syntax is wrong, and that you don't construct the K object in the "raw" storage. Here's a corrected version:
#include <string>
#include <iostream>
class K{
public: std::string yes="yes" ;
};
int main() {
//objective: k1->raw->k2 , then delete "raw"
alignas(alignof(K)) char raw[sizeof(K)]; //<--- try to avoid heap allocation
K k1;
new (reinterpret_cast<K *>(&raw)) K(k1); //<--- compile now succeeds :)
K k2= reinterpret_cast<K &>(raw);
std::cout << k2.yes << std::endl; //test
reinterpret_cast<K&>(raw).K::~K(); // call destructor
return 0;
}
How can I give values of my new initialized array if I am using a pointer? E.g.
int* array = new int[3]; <- I want to give the values {1,2,3} on the same row but not:
array[0] = 5;
array[1] = 3;
array[2] = 4;
You can use a brace enclosed initializer:
int* array = new int[3]{1, 2, 3};
The usual warning is that you would need to ensure that you call delete [] on array. This is harder to guarantee than apears at first sight. For this and other reasons, it may be a better idea to use an std::vector<int>:
std::vector<int> v{1,2,3};
If you are stuck with an older, pre-C++11 implementation, then you cannot use the brace enclosed initializer syntax. You will have to use a loop at some level (whether your own, or by using some standard or 3rd party library function.)
If you absolutely, positively have to use C++98, you could do something like this:
#include <algorithm> //copy
#include <iostream> // cout
#include <iterator> // iostream_iterator
void foo()
{
int init[] = { 1, 2, 3 };
int* array = new int[3];
std::copy(init, init + 3, array);
std::copy(array, array + 3, std::ostream_iterator<int>(std::cout, ", "));
// better hope nothing bad like an exception happens in between
delete[] array;
}
int main()
{
foo();
}
Live Example. So you define a C-array of initializers and copy them into your dynamically allocated array. The C-array init will be automatically deleted when foo() exits, but you have to manually delete array. The recommended way is to use std::vector in C++11 with an initializer-list.
How would one access an entire row of a multidimensional array?
For example:
int logic[4][9] = {
{0,1,8,8,8,8,8,1,1},
{1,0,1,1,8,8,8,1,1},
{8,1,0,1,8,8,8,8,1},
{8,1,1,0,1,1,8,8,1}
};
// I want everything in row 2. So I try...
int temp[9] = logic[2];
My attempt throws the error:
array initialization needs curly braces
I know I can retrieve the row using a FOR loop, however I'm curious if there was a more obvious solution.
That's not how arrays/pointers work in C++.
That array is stored somewhere in memory. In order to reference the same data, you'll want a pointer that points to the the beginning of the array:
int* temp = logic[2];
Or if you need a copy of that array, you'll have to allocate more space.
Statically:
int temp[9];
for (int i = 0; i < 9; i++) {
temp[i] = logic[2][i];
}
Dynamically:
// allocate
int* temp = new int(9);
for (int i = 0; i < 9; i++) {
temp[i] = logic[2][i];
}
// when you're done with it, deallocate
delete [] temp;
Or since you're using C++, if you want to not worry about all this memory stuff and pointers, then you should use std::vector<int> for dynamically sized arrays and std::array<int> for statically sized arrays.
#include <array>
using namespace std;
array<array<int, 9>, 4> logic = {
{0,1,8,8,8,8,8,1,1},
{1,0,1,1,8,8,8,1,1},
{8,1,0,1,8,8,8,8,1},
{8,1,1,0,1,1,8,8,1}
}};
array<int, 9> temp = logic[2];
As well as decaying the array to a pointer, you can also bind it to a reference:
int (&temp)[9] = logic[2];
One advantage of this is it will allow you to use it C++11 range-based for loops:
for (auto t : temp) {
// stuff
}
A direct assignment won't work. C++ does not allow that. At best you'll be able to assign them to point to the same data - int *temp = logic[2]. You'll need a for loop or something like the below.
I believe this would work:
int temp[9];
memcpy(temp, logic[2], sizeof(temp));
But I'd generally suggest using std::vector or std::array instead.
It is possible to give an initializer list to the definition of a static array. Example:
int main()
{
int int_static[2] = {1,2};
}
Is a similar initializer list possible for a dynamic array?
int main()
{
int* int_ptr = new int[2];
}
This is closer to what I am trying to do:
struct foo
{
foo(){}
foo(void * ptr): ptr_(ptr) {}
void * ptr_;
};
int main()
{
foo* foo_ptr = new foo[10];
}
At initialization time not the default constructor should be called, but foo:foo(void*).
The point of having a static initializer list for a dynamic array might come handy in the case of Just-In-Time compilation for accelerator cores which do have only a limited amount of stack available, but at the same time you construct your objects with a (accelerator compile time = host run time) static initializer list.
I assume not (since this would require the compiler to generate additional code, namely to copy the values of the arguments to the heap location). I think c++0x supports some of this, but I cannot use it.
Right now I could use such a construct. Maybe someone knows a trick..
Best!
At the time the OP posted this question, C++11 support may not have been very prevalent yet, which is why the accepted answer says this is not possible. However, initializing a dynamic array with an explicit initializer list should now be supported in all major C++ compilers.
The syntax new int[3] {1, 2, 3} was standardized in C++11. Quoting the new expression page on cppreference.com:
The object created by a new-expression is initialized according to the following rules:
...
If type is an array type, an array of objects is initialized:
...
If initializer is a brace-enclosed list of arguments, the array is aggregate-initialized. (since C++11)
So, given the OP's example, the following is perfectly legal when using C++11 or newer:
foo * foo_array = new foo[2] { nullptr, nullptr };
Note that by providing pointers in the initializer list, we're actually coaxing the compiler to apply the foo(void * ptr) constructor (rather than the default constructor), which was the desired behavior.
No, you cannot do that.
I think C++ doesn't allow this because allowing such thing doesn't add any nice-to-have feature to the language. In other words, what would be the point of dynamic array if you use a static initializer to initialize it?
The point of dynamic array is to create an array of size N which is known at runtime, depending on the actual need. That is, the code
int *p = new int[2];
makes less sense to me than the following:
int *p = new int[N]; //N is known at runtime
If that is so, then how can you provide the number of elements in the static initializer because N isn't known until runtime?
Lets assume that you're allowed to write this:
int *p = new int[2] {10,20}; //pretend this!
But what big advantage are you getting by writing this? Nothing. Its almost same as:
int a[] = {10,20};
The real advantage would be when you're allowed to write that for arrays of N elements. But then the problem is this:
int *p = new int[N] {10,20, ... /*Oops, no idea how far we can go? N is not known!*/ };
No, you will have to create the elements dynamically.
Alternatively, you can use a local array and copy its elements over those of the dynamically allocated array:
int main() {
int _detail[] = { 1, 2 };
int * ptr = new int[2];
std::copy( _detail, _detail+(sizeof detail / sizeof *detail), ptr );
delete [] ptr;
}
In the limited version of setting all elements to 0, you can use an extra pair of parenthesis in the new call:
int * ptr = new int[2](); // will value initialize all elements
But you seem to be looking for a different thing.
Given that you're real class is more complex than an int, and constructed from differing values, it's complicated.
A vector can be constructed with iterators if you have an existing array/vector with the correct values to default from, or you have to use placement new.
//vector
int main()
{
int int_static[2] = {1,2};
std::vector<int> int_dynamic(int_static, int_static+2);
//this is what everyone else is saying. For good reason.
}
//placement new
int function_that_returns_constructed_from_values() {
return rand();
}
int main()
{
int count = 2;
char *char_dynamic = new char[count * sizeof(int)];
int *int_dynamic = char_dynamic;
for(int i=0; i<count; ++i)
new(int_dynamic+i)int(function_that_returns_constructed_from_values());
//stuff
for(int i=0; i<count; ++i)
(int_dynamic+i)->~int(); //obviously not really int
delete []char_dynamic;
}
Obviously, the vector is the preferred way to do this.
The initializer data must be somewhere anyway. Simply name it.
E.g.,
#include <stddef.h>
#include <algorithm> // std::copy
#include <vector>
typedef ptrdiff_t Size;
template< class Type, Size n >
Size countOf( Type (&)[n] ) { return n; }
int main()
{
using namespace std;
static int const initData[] = {1,2};
static Size const n = countOf( initData );
// Initialization of a dynamically allocated array:
int* pArray = new int[n];
copy( initData, initData + n, pArray );
// Initialization of a vector:
vector<int> v( initData, initData + n );
}
EDIT: fixed a thinko in above code. I hastened to add example on request. So what I put did erroneously use return value from std::copy.
Cheers & hth.,