I have a class lets say aClass
class aClass
{
public:
int data;
aClass(): data(-1) { //default constructor
}
aClass(int x): data(x) { //int constructor
};
If I create an array like
aClass* arr=new aClass[10];
Question 1:
I was thinking no aClass object has been created since it is just a declaration of an array, but in a program that I tested it looks like arr[0] to arr[9] all points to a aClass object created by default constructor in its class? Because I had tested the program and the result is a[0].data=-1 all the way to a[9].data=-1.
Question 2: if objects are created with their default constructor, how am I supposed to create an array that has objects created by int constructor? obviously I can't write code like
aClass* arr=new aClass(2015)[10];
Quesntion 1: I was thinking no aClass object has been created since it is just a declaration of an array
You were thinking wrong. It's a declaration of a pointer which is initialized with the return value of new aClass[10] which constructs an array of 10 objects.
but in a program that I tested it looks like arr[0] to arr[9] all points to a aClass object created by default constructor in its class?
Yes, your observation is correct.
Question 2: if objects are created with their default constructor, how am I supposed to create an array that has objects created by int constructor?
Since c++11 you can use list initialization: aClass *foo = new aClass[3]{1, 2, 3}; as chris pointed in a comment.
You may want to use std::vector instead. There is std::vector::vector(size_type n, const value_type& val) for constructing copies and since c++11: std::vector::vector(initializer_list<value_type>) for different values.
With static/automatic arrays aggregate initialization was possible even before c++11:
aClass foo[3] = { 1, 2, 3 };
Instead of aClass* arr=new aClass(2015)[10];
You could do aClass *arr = new aClass[10]{2015, 2015/*etc*/}; if your compiler supports it.
In C++11, both of these mean the same thing.
aClass *arr = new aClass[10];
aClass *arr = new aClass[10]{};
Better alternative would be to use std::vector and avoid using raw pointers and instead use smart pointers ex. std::unique_ptr.
Example of this alternative could be:
int main()
{
vector<unique_ptr<aClass>> vec;
for (int i{0}; i != 10; ++i)
vec.emplace_back(new aClass(2015));
for (auto const& i : vec) // print data
cout << i->data << endl;
return 0;
}
Regarding question 1. The rules for initialization are very rigid. Your array new[] expression creates an array of values. Those values must be initialized and by default they use default initialization.
The answer to question 2 is that you can't do that with dynamic arrays. However, std::vector does provide a constructor that allows you to provide an object that will be copied to each of the contained elements. See explicit vector(size_type count, const T& value = T(), const Allocator& alloc = Allocator()).
If you want each element in the collection to be different, then you must use a loop and assign the elements individually unless the size of the array is determined statically in which case you can use initializer expressions. If you want to avoid the initial default construction for dynamic containers, then you should not store the objects by value. You should use a container of pointers or better yet a container of smart pointers. Then you can use direct initialization for each object.
You need to create array of pointers if you want to create an array without creating the objects. For example, aClass** arr = new aClass*[10]; creates an array of pointers. And when you want to create the actual objects, you need to do something like this: arr[0] = new aClass(2015);
Related
I have a shared array, it is something like that
class Array
{
public:
// basic array opertion like resize, operator[], etc, like std::vector
private:
int size;
std::shared_ptr<int> data;
};
It do the shallow copy in copy constrcutor and copy assigen operator.
The memory of Array is controlled by std::shared_ptr to ensure no memory leak can happen.
Now I have a class, ArrayContainer , it have Array as the member.
I need let others access the class member. but I do not want others change it. My design is follow, but it is not good.
class ArrayContainer
{
public:
void calculation()
{
// do some operation on array ...
}
// it is not a safe interface, althogh const, others still can change the member
const Array &getArray() const
{
return this->array;
}
private:
Array array;
};
Using my interface, one may access the member in ArrayContainer by follow ways.
// example 1: safe use array
ArrayContainer container;
const Array &array = container.getArray();
// follow using array will not influence the member in user.
// example 2: may be not safy use array
ArrayContainer container;
Array array = container.getArray();
// follow using array may modify the array in container, it is not safe.
My problem is: I do not want to other's may change the member in ArrayContainer. What is a elegant way to access a shared array in class with safety?
Thanks for your time.
I don't understand why you are using std::shared_ptr, since you want memory leak to not happen.
I suppose you are using std::shared_ptr<int[]> data, and not std::shared_ptr<int> data;
I guess enough for you to use std::unique_ptr, and don't share your memory.
Anyway you need to add copy constructor to full copy array data, because in this case
ArrayContainer container;
Array array = container.getArray();
will be called copy constructor
You can do it like below
Array(const Array& array) {
for (int i = 0; i < array.size; ++i) {
data.get()[i] = array.data.get()[i];
}
}
I need to use array as a class property but I am not sure about the correct way. Assume that I have a class called A and I need an integer array in it.
First, if I want a static array with 10 elements, is the following way correct? If not, how should it be?
class A {
public:
int arr[10];
};
Second, if I want a dynamic array, which one of the followings is correct? If neither of them, I would be appreciated if you explain the reason and correct way.
class A {
public:
int *arr;
};
class A {
public:
int arr[];
};
Finally, what happens if I initialize a property in class definition as following
class A {
public:
int arr[] = {1,2,3};
// or
int *arr = new int[5];
// or
int number = 5;
};
Thanks a lot.
Note: I am aware of that it is much better to use vector or that kind of STL data structure but I need to stick to arrays somehow.
First, if I want a static array with 10 elements, is the following way correct?
Yes, that is a correct way.
Some people prefer to wrap the array in a class template such as std::array.
Second, if I want a dynamic array, which one of the followings is correct? If neither of them, I would be appreciated if you explain the reason and correct way.
class A {
public:
int arr[];
};
That is an ill-formed declaration. A member cannot be an array of indeterminate length.
class A {
public:
int *arr;
};
This is correct as such, but there is no dynamic array created. Using this for owning a dynamic array is bad design because bare pointers should never have ownership.
Even for pointing an array stored elsewhere, this is problematic since the class has no knowledge of the length of the array.
This would be a correct way, assuming the array is owned by the class:
class A {
public:
std::vector<int> arr;
};
If the array isn't owned by the class, then following is correct:
class A {
public:
std::span<int> arr;
};
std::span isn't in the standard until C++20 though, so until then you need to resort to a non-standard implementation.
Finally, what happens if I initialize a property in class definition as following
class A {
public:
int arr[] = {1,2,3};
That is ill-formed because the size of a member cannot be deduced from the initaliser.
int *arr = new int[5];
new int[5] is a default member initialiser. It will be used in case no initialiser is provided for the member otherwise.
For fixed-size arrays you can use int arr[10] or std::array<int, 10>.
For dynamically-sized or resizeable arrays if you cannot use std::vector or std::unique_ptr<int[]> you should use int* (int[] is not a valid data member type in C++) and implement constructor, copy constructor, move constructor, copy assignment, move assignment and destructor. See rule of five for more details.
How do I switch both parameters of the class to the object that I am creating with a pointer? What is the syntax? (They must receive all the same parameters)
In a normal situation I use this:
MyClass obj[5]={MyClass(x,y)}
But... in this case what is the syntax? :
MyClass *obj;
obj = new MyClass[5]; //Here! <----
How can I pass the two parameters?
There is no syntax to list-initialize a dynamically allocated array.
You must
Either 1) default construct as in the example you show, and modify the objects after creation.
Or 2) allocate an array of char of sufficient size, and construct the objects with placement-new.
1) is not an option if the class is not default constructible. 2) is a bit complicated, but you don't have to do that yourself since std::vector has already implemented it for you. You should be using vector anyway since it takes care of memory management.
An example with vector, that is analogous to your "normal situation". Note that your "normal situation" doesn't match the description in your question:
std::vector<MyClass> v{
{x1, y1},
{x2, y2},
...
};
An example with vector, that matches your description of passing same argument to all objects in the array. Although technically, this copy-constructs the array elements:
std::vector<MyClass> v(5, {x, y});
I'm assuming that your question is: "how do I initialize all the objects in an array with the exact same constructor call?"
If that's the case, the easiest way of doing so is using std::vector's constructor (2):
vector( size_type count,
const T& value,
const Allocator& alloc = Allocator());
Constructs the container with count copies of elements with value value.
Your example then becomes:
std::vector<MyClass> obj(5, MyClass{x, y});
If you really want to use a C-style array, you will have to manually invoke constructors using placement new and manually invoke destructors if you want to avoid unnecessary default constructor calls. Example:
std::aligned_storage_t<sizeof(MyClass), alignof(MyClass)> obj[5];
for(auto& x : obj) { new(&x) MyClass{x, y}; }
// ... use `obj` ...
for(auto& x : obj) { reinterpret_cast<MyClass*>(&x)->~MyClass(); }
Note that the above code can be (and should be) refactored into a safe abstraction.
From here http://www.cplusplus.com/reference/new/operator%20new[]/, it is unclear to me is it possible to allocate and construct objects with parameters. Like this:
struct MyClass {
int data;
MyClass(int k) {}
};
int main () {
// allocates and constructs five objects:
MyClass * p1 = new MyClass[5](1); // allocate 5 objects, and init all with '1'
}
Which is not work...
That wouldn't work, but you can use an std::vector<MyClass> for that:
std::vector<MyClass> p1(5, 1);
This will create a vector containing 5 MyClass objects. Note that this works because your single parameter constructor is not explicit. If it were, you would need
std::vector<MyClass> p1(5, MyClass(1));
What you wrote does not work, but you could do this since C++11.
Still, better avoid dynamic allocation and go for automatic object.
Also, most times you really should use a standard container like std::array or std::vector.
MyClass * a = new MyClass[5]{1,1,1,1,1};
MyClass b[5] = {1,1,1,1,1};
std::vector<MyClass> c(5, 1);
std::vector<MyClass> d(5, MyClass(1));
std::array<MyClass,5> e{1,1,1,1,1};
I would like to know, if I have a class with an array attribute whose size is not the same for all instances :
class myObject{
private:
int size;
int* array;
// other methods/attributes
};
Is it obligatory allocated using new ?
explicit myObject(int size = 0):size(size){
array = new int[size];
}
Even if in the main(), I always use constant parameters to create the instances of the class ? (Meaning I know every array size at compile time).
int main{
myObject object (5);
return 0;
}
Apparently something like :
private:
int size;
int array[size];
wont work, no ?
That means that array attribute whose size are not constant of the class are obligatory on the heap ?
Thank you for your answers,
That class contains no array. What you called array is a pointer; you cannot store any ints in it. If you really do just store a pointer, you'll have to allocate the memory yourself somehow; it can't magically appear. You'll also have to deallocate it yourself, and make sure that copying and assigning myObject objects doesn't cause any issues.
However, it's unlikely that a pointer is really the best way to do things. The standard library provides the std::vector class template which lets you use almost exactly the syntax you want:
class myObject {
std::vector<int> vector;
public:
myObject() {};
explicit myObject(std::size_t n) : vector(n) {}
};
With this in place you can create myObjects and they'll have the right amount of storage ready for them. It'll likely be dynamically allocated using operator new[], just like if you'd do it manually, but you don't have to worry about copying or deleting it.
int main() {
myObject a; // default-constructed, vector is empty.
myObject b(10); // std::size_t constructor, vector has 10 elements.
} // scope exit, b and a destroyed.
You can use the vector member much like if it was an array; the only thing it does not support is implicit decay to pointer, but the data member function makes up for even that.
As an alternative, if you always know the size at compile-time you can change the class into a class template and make the size a template parameter:
template<std::size_t N>
class myObject{
std::array<int, N> array;
// other methods/attributes
};
However, note that you now cannot use myObject<10> to a function expecting myObject<20>.
It is unlikely that you want more control than the above possibilities provide -- std::vector can be given an allocator, so it can do almost all work for you -- you could use std::unique_ptr<int[]> and make_unique together to make things work for you. However, if you need this kind of power, you probably know it yourself.
As a closing note, if you're just learning C++ and your book doesn't cover std::vectors somewhere early on, perhaps it's best to get a different book; they're one of the most commonly-useful data structures in the standard library and definitely not something to be left in an appendix.
If you need a variable sized array as a member of a class, don't use built-in arrays directly. Instead, use std::vector<T>, e.g.:
class myObject {
std::vector<int> array;
public:
explicit myObject(int size = 0): array(size){}
};
You can get the std:vector<int>'s size using array.size(), i.e., there is no need to store the size separately. Also, the content is automatically default initialized.