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.
CodePudding user response:
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{};
CodePudding user response:
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.
CodePudding user response:
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.
CodePudding user response:
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!!
}