'How to initialize a pointer to an array in a class constructor?
I have this code
template <class ItemType>
class ArrTest {
public:
ArrTest();
private:
ItemType* info;
};
template <class ItemType>
ArrTest<ItemType>::ArrTest()
{
info = ItemType[50];
}
int main() {
ArrTest<int> ar();
return 0;
}
Right now when I try and build this I get
../src/test1.cpp:23:9: error: 'ItemType' does not refer to a value
info = ItemType[50];
I don't understand how to initialize this into pointer. I believe its a pointer to the first item in the array. but then I should also be able to do info[3] for the 4th member of the array for instance.
Solution 1:[1]
You need to use the new[] operator to allocate the array dynamically:
template <class ItemType>
ArrTest<ItemType>::ArrTest()
: info(new ItemType[50])
{
}
And then, be sure to add a destructor to delete[]'s the array, and also add copy/move constructors and copy/move assignment operators, per the Rule of 3/5/0:
template <class ItemType>
class ArrTest {
public:
ArrTest();
ArrTest(const ArrTest &src);
ArrTest(ArrTest &&src);
~ArrTest();
ArrTest& operator=(ArrTest src);
private:
ItemType* info;
};
template <class ItemType>
ArrTest<ItemType>::ArrTest()
: info(new ItemType[50])
{
}
template <class ItemType>
ArrTest<ItemType>::ArrTest(const ArrTest &src)
: info(new ItemType[50])
{
std::copy(src.info, src.info + 50, info);
}
template <class ItemType>
ArrTest<ItemType>::ArrTest(ArrTest &&src)
: info(nullptr)
{
std::swap(info, src.info);
}
template <class ItemType>
ArrTest<ItemType>::~ArrTest()
{
delete[] info;
}
template <class ItemType>
ArrTest<ItemType>& ArrTest<ItemType>::operator=(ArrTest<ItemType> src)
{
std::swap(info, src.info);
return *this;
}
A better solution would be to use std::vector instead, and let it handle all of these details for you, eg:
#include <vector>
template <class ItemType>
class ArrTest {
public:
ArrTest();
private:
std::vector<ItemType> info;
};
template <class ItemType>
ArrTest<ItemType>::ArrTest()
: info(50)
{
}
Either way, ArrTest<int> ar(); does not declare a default-constructed variable named ar of type ArrTest<int>, like you are expecting. It declares a function named ar that takes no parameters and returns an ArrTest<int>, which is not what you want.
To avoid that, you need to either:
drop the parenthesis:
ArrTest<int> ar;replace the parenthesis with curly braces:
ArrTest<int> ar{};
Solution 2:[2]
This construction
info = ItemType[50];
is syntactically invalid. ItemType is a type as for example int because it is a type template parameter. So you have similarly to
info = int[50];
but the right side expression is not an object. It is a type specifier. So the compiler issues a compilation error.
Pay attention to that if you will write something like the following
template <class ItemType>
ArrTest<ItemType>::ArrTest()
{
ItemType a[50];
info = a;
}
then the pointer info will have an invalid value because the local array a defined in the constructor will not be alive after exiting the constructor.
Solution 3:[3]
You can use constructor initializer list and new, as shown below:
template <class ItemType>
//----------------------------vvvvvvvvvvvvvvvvvvvvvv-->added this
ArrTest<ItemType>::ArrTest(): info(new ItemType[50])
{
}
Also note that ArrTest<int> ar(); declares a function named ar with the return type of ArrTest<int> and that takes no parameters. If your intention was to create an object of type ArrTest<int> then, you can replace it with:
ArrTest<int> ar{};
Also, don't forget to have a corresponding delete[] to free the allocated memory when no longer needed or use a std::vector so that you don't have to do manual memory management.
Solution 4:[4]
Some answer suggested the use of new or, even better, std::vector. If the
number element is fixed and known at compile-time (e.g. 50), you may consider a
std::array:
#include <array>
template <class ItemType>
class ArrTest {
public:
private:
std::array<ItemType, 50> info;
};
or a C-style array:
template <class ItemType>
class ArrTest {
public:
private:
ItemType info[50];
};
With these solutions, you don't need to implement destructor, copy/move
constructors and copy/move assignment operators. With respect to the
std::vector solution, you're not allocating memory on the heap, since array
info leaves on the stack. The downside is that the move operations will cost
you O(sizeof(info) / sizeof(ItemType)) instead of O(1).
Also, beware that:
int main() {
ArrTest<int> ar0{};
// ^ This has all its elements initialized to int{} (i.e. (int)0)
ArrTest<int> ar1;
// ^ This has all its elements uninitialized!!
//ArrTest<int> ar2();
// ^ This declares a function!!
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | |
| Solution 4 |
