how to access a const shared array safe in a class - c++

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];
}
}

Related

Does delete[] work properly with generic arrays? If so why does using std::vector::erase on it cause error in freeing memory

I was trying to work with arrays that are circular, and so ended up writing a CircularArray class for which I have attached the code. It uses a generic pointer for an array.
When I try creating a list of such circular arrays using std::vector, I face a problem when I try to use erase on it.
I don't see why this should be the case as I think the destructors and copy constructor work well enough normally.
Can someone please help with this?
Code:
CircularArray Class
template<class T> class CircularArray
{
//Class denoted by 'T' is expected to have a functional assignment operator, i.e. operator=(const T& ext) {} in place
protected:
int size=0;
int ori=0;
T* array;
private:
int pos=0;
public:
CircularArray() : CircularArray(0) {}
CircularArray(int s) {size=s;array=new T[s];}
CircularArray(T* ptr,int s)// : CircularArray(s)
{
size=s;array=new T[s];
for(int i=0;i<size;i++)
array[i]=ptr[i];
}
CircularArray(const CircularArray<T>& arr) : CircularArray(arr.size)
{
for(int i=0;i<size;i++)
array[i]=arr.array[i];
}
~CircularArray() {delete[] array;}
...
Testing Code
int main()
{
std::vector<CircularArray<int>> test;
int *a1=new int[3] {1,2,3},*a2=new int[3] {1,2,3},*a3=new int[3] {1,2,3};
CircularArray<int> n1(a1,3),n2(a2,3),n3(a3,3);
test.push_back(n1);
test.push_back(n2);
test.push_back(n3);
test.erase(test.begin()+1);
for(auto v : test)
{
for(int i=0;i<3;i++)
cout << v[i];
cout << "\n";
}
}
This program gives bad output after encountering the deleted part of the vector. Valgrind says that there is a memory corruption in trying to read freed memory.
What is wrong?
Vector elements must be copy/move assignable, yet you are relying on the default copy assignment operator which does not create any fresh memory. Your assigned objects all share the same memory space, later resulting in a double free.
Your constructors are good but you'll need a copy/move assignment operator too.
Read about the Rule of Five.
Also consider just using a std::vector for backing storage; it'll be much simpler.
Does delete[] work properly with generic arrays?
Yes.
Your (implicitly generated) copy and move assignment operator are wrong. They will copy the member pointer. Then you have two pointers to the same array, and one destructor deletes it once, and another deletes it for a second time, which leads to undefined behaviour.
When manually managing dynamic resource, it is essential to keep track of ownership, and make sure that it is released exactly once. A typical solution is to use a smart pointer. Your class has unique ownership (or it would have, if it didn't accidentally share the ownership in the assignment operators) of the dynamic array, so a unique pointer would be an appropriate choice.
On the other hand, you could use a vector container instead of a smart pointer.

Array elements automatically created by default constructor?

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);

C++ : Allocation of an array attribute in a class

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.

Is it possible to write a "complete" C++ class with Zero Length Array member?

I have some data type which, if I were to use plain old C, would be implemented as
typedef struct {
...many other members here...
unsigned short _size;
char _buf[0];
} my_data;
What I'd like to do, is to basically make that a class and add the usual operators like less, equality, copy constructor, operator assignment, and so on. As you can imagine I would then be using such class in associative containers like std::map as its key.
I need the buffer to be ideally at the same level of the object itself, otherwise when I have to compare two of them (buffers) I would have the CPU to take the pointer and load it in memory; I don't want to use std::vector because memory allocated wouldn't be contiguous with the rest of the data members.
Main issue for me is the fact that in C I would have a function which, given the size of the buffer would allocate proper memory size for it. In C++ such thing can't be done.
Am I right?
Cheers
This is quite impossible. Your object is effectively of variable size but the std::map will always treat it as a fixed size, and there is no way to implement copying or moving. You would need an old C-style container to use such a hack.
Edit: Custom allocator. Interesting solution, I hadn't thought of that. I don't know if you could make it work but it would be worth looking into.
No, it's not possible. Zero length arrays aren't legal C++.
You can1 do something very similar with an array of length 1, but you would still have to manage creation of instances yourself, so no copy constructor and no storing the objects in std::map.
Perhaps something like this:
class my_data {
public:
static my_data* create(int size) {
void* memory = malloc(sizeof(_size) + size);
return new(memory) my_data(size);
}
static void destroy(my_data* ptr) {
ptr->~my_data();
free(ptr);
}
private:
//disable construction and destruction except by static methods above
explicit my_data(int size) : _size(size) {}
~my_data(){}
//disable copying
my_data(const my_data&);
my_data& operator=(const my_data&);
unsigned short _size;
char _buf[1];
};
Note that the default constructor, destructor, copy constructor and assignment operator are all private, which greatly restricts how the class can be used.
1 In practical terms - it's not standards compliant, but it will work almost everywhere.
You can approach it this way in C++:
struct MyData {
unsigned short size_;
char * buf () { return reinterpret_cast<char *>(&size_ + 1); }
//...
};
You are likely going to want to overload the new operator to use malloc, and delete to use free, so that you can grow your data structure on demand with realloc.
As DeadMG points out, this cannot be used with STL containers very easily. One approach would be to use pointers to MyData in the containers. Another would be a custom smart pointer wrapper class for MyData.
Edit: This is a hack, where MyData acts as a kind of smart pointer, but the intelligence is managed by vector.
struct MyData {
struct State {
unsigned short size_;
//...
};
std::vector<State> data_;
MyData () {};
MyData (unsigned short size)
: data_(1 + size/sizeof(State) + !!size%sizeof(State)) {
data_[0].size_ = size;
}
unsigned short size () const { return data_[0].size_; }
//...
char * buf () { return reinterpret_cast<char *>(&data_[1]); }
};

Array as private member of class

I am trying to create a class which has a private member that is an array. I do not know the size of the array and will not until the value is passed into the constructor. What is the best way to go about defining the class constructor as well as the definition in the .h file to allow for this variable size of the array?
If you want a "real" C-style array, you have to add a pointer private member to your class, and allocate dynamically the memory for it in the constructor (with new). Obviously you must not forget to free it in the destructor.
class YourClass
{
private:
int * array;
size_t size;
// Private copy constructor operator to block copying of the object, see later
// C++03:
YourClass(const YourClass &); // no definition
// C++11:
YourClass(const YourClass&) = delete;
public:
YourClass(size_t Size) : array(new int[Size]), size(Size)
{
// do extra init stuff here
};
~YourClass()
{
delete [] array;
}
};
To make this work easier, you may consider to use a smart pointer (for example, a boost::scoped_array in C++03, or plain std::unique_ptr in C++11), that you may initialize using the initializer list before the constructor or simply in the constructor.
class YourClass
{
private:
boost::scoped_array<int> array; // or in C++11 std::unique_ptr<int[]> array;
size_t size;
public:
YourClass(size_t Size) : array(new int[Size]), size(Size)
{
// do extra init stuff here
}
// No need for a destructor, the scoped_array does the magic
};
Both these solutions produce noncopyable objects (you didn't specify if they had to be copyable and their copy semantic); if the class don't have to be copied (which happens most of times), these both are ok, and the compiler will generate an error if you try to copy/assign one class to another, in the first case because the default copy constructor has been overloaded with a private one (or plain deleted in C++11), in the second case because boost::scoped_array and std::unique_ptr are noncopyable.
If, instead, you want to have copyable objects, then you must decide if you want to create a copy that shares the array (so, just a pointer copy) or if you want to create a new, separate array for the other object.
In the first case, you must be very careful before freeing the allocated memory, since other objects may be using it; a reference-counter is the most common solution. You can be helped in this by boost::shared_array (or std::shared_ptr in C++11), which does all the tracking work automatically for you.
If instead you want to do a "deep copy", you'll have to allocate the new memory and copy all the objects of the source array to the target array. This is not completely trivial to do correctly, and is usually accomplished through the "copy and swap idiom".
Still, the simplest solution is to use a std::vector as a private member: it would handle all the allocation/deallocation stuff by itself, constructing/destroying itself correctly when the object of your class is constructed/destructed. Moreover, it implements the deep-copy semantic out of the box. If you need to make your callers access the vector read-only, then, you could write a getter that returns a const_iterator or a const reference to the vector object.
Using a std::vector is the best option.
If you ever need to pass it to a function that expects a pointer to an array (like the GSL often does), you can still pass &vec[0]...