struct Mystruct
{
int x;
int y;
Mystruct(int x, int y);
}
------------------------
class Myclass
{
Mystruct** p;
Myclass(int n);
}
------------------------
Myclass::Myclass(int n)
{
this->p = new Mystruct*[n];
for ( int i = 0; i < n; i++ )
this->p[i] = new Mystruct[n];
}
This will not work. I know the problem lies somewhere with default constructor not being available, but I do not know how to move forward from here.
you want
Myclass::Myclass(int n)
{
this->p = new Mystruct*[n];
for ( int i = 0; i < n; i++ )
this->p[i] = new Mystruct[n];
}
because Mystruct** p;
You also need to save the dimension, and to add a destructor, very probably the constructor must be public.
As said in a remark to be able to allocate your array of Mystruct that one need a constructor without parameter
Related
I have the following class which simply wraps an array and adds with the constructor some elements to it:
class myArray {
public:
myArray();
myArray(int a, int b);
myArray(int a, int b, int c);
myArray(myArray&& emplace);
~myArray();
int& operator [](int id);
private:
int *data;
};
myArray::myArray() {
data = new int[1];
data[0] = 0;
}
myArray::myArray(int a, int b) {
data = new int[3];
data[0] = 0;
data[1] = a;
data[2] = b;
}
myArray::myArray(int a, int b, int c) {
data = new int[4];
data[0] = 0;
data[1] = a;
data[2] = b;
data[3] = c;
}
myArray::~myArray() {
std::cout << "Destructor"<<std::endl;
delete[] data;
}
int& myArray::operator [](int id) {
return data[id];
}
myArray::myArray(myArray&& emplace) : data(std::move(emplace.data)) {}
Furthermore I have a second class which contains a vector of elements of the first class (myArray).
class Queue {
public:
Queue();
private:
std::vector<myArray> _queue;
};
Queue::Queue {
_queue.reserve(1000);
for(int a = 0; a < 10; a++)
for(int b = 0; b < 10; b++)
for(int c = 0; c < 10; c++)
_queue.emplace_back(a,b,c);
}
My question here is: Why is the destructor called for the myArray elements at the end of the Queue constructor? The Queue object is still alive in my main program but the destructor of myArray frees the allocated memory and I consequently get a segmentation fault.
Is there a way to avoid the call of the destructor or rather call it not until at the end of the Queue objects lifetime?
Your move constructor doesn't set data to null on the moved from object so when the moved from object is destructed it will try to free data.
If you have c++14 you can use std::exchange to implement this:
myArray::myArray(myArray&& emplace)
: data{std::exchange(emplace.data, nullptr)})
{}
Otherwise you need to do:
myArray::myArray(myArray&& emplace)
: data{emplace.data)
{
emplace.data = nullptr;
}
The move constructor will be invoked by std::vector as it reallocates to increase its capacity when you call emplace_back. Something like the following steps are performed:
Allocate new memory to hold the elements
Move construct using placement new elements in the new memory from the elements in the previous memory
Destruct the elements in the previous memory
Deallocate the previous memory
I got stuck with deleting an dynamically allocated array of int.
I've got a destructor, where I'm trying to use a loop for to delete all elements of array and finally delete it.
I have code on http://rextester.com/OTPPRQ8349
Thanks!
class MyClass
{
public:
int _a;
int* c;
int fRozmiar;
static int fIlosc;
MyClass() //default constructor
{
_a=0;
c = new int [9];
for(int i = 0; i<=9; i++)
{
c[i] = 1;
}
fIlosc++;
}
MyClass(int a1, int c1) // parametrized constructor
{
_a=a1;
c = new int [c1];
for(int i = 0; i<=c1; i++)
{
c[i] = rand();
}
fIlosc++;
}
MyClass(const MyClass &p2) // copy constructor
{
_a =p2._a;
c = p2.c;
fRozmiar = p2.fRozmiar;
fIlosc = fIlosc;
fIlosc++;
}
~MyClass(); // destructor
static int getCount() {
return fIlosc;
}
};
//Initialize static member of class
int MyClass::fIlosc = 0;
MyClass::~MyClass()
{
for(int i = 0; i<sizeof(c); ++i)
{
delete[] c[i];
}
delete[] c;
fIlosc--;
}
int main()
{
}
Remove the for-loop, but keep the delete[] c after it.
Each int doesn't need to be deleted because they're not dynamically allocated. If you needed to delete them, then the for-loop wouldn't work becuase: sizeof(c) is not the size of the array, and delete[] should have been delete instead.
There are several problems in the code.
First, that loop in the destructor must go. If you didn’t new it, don’t delete it.
Second, a loop through an array of N elements should be for (int i = 0; i < N; ++i). Note that the test is i < N, not i <= N. The loops as currently written go off the end of the array. That’s not good.
Third, the copy constructor copies the pointer. When the first object goes out of scope its destructor deletes the array; when the copy goes out of scope its destructor also deletes the array. Again, not good. The copy constructor has to make a copy of the array. In order to do that the class needs to also store the number of elements the array.
Given a class Foo which has some value-initializing default constructor:
class Foo {
private:
uint32_t x;
public:
constexpr Foo()
: x { 3 }
{}
// ... and some other constructors
};
I need to allocate an array of these Foo's. I don't want the array's elements' default constructors to run, because later I'm going to initialize each element explicitly anyway. Something like this:
Foo foos[20000];
for (int i = 0; i < 20000; ++i) {
foos[i] = init(i);
}
Is there a way to obtain such an uninitialized array of Foo's given that we're not allowed to change the default constructor of Foo into a non-initializing one?
By the way, this is how you'd create an uninitialized array in D:
Foo[20000] foos = void;
...and here's the same in Rust:
let mut foos: [Foo; 20000] = unsafe { std::mem::uninitialized() };
If you using C++11, you can use std::vector and emplace_back()
vector<Foo> foos;
for(int i = 0; i < 20000; ++i)
foos.emplace_back( /* arguments here */);
Perhaps this answers the question at hand more accurately?
#include <type_traits>
class Foo {
private:
uint32_t x;
public:
constexpr Foo()
: x { 3 }
{}
constexpr Foo(uint32_t n)
: x { n * n }
{}
};
// ...and then in some function:
typename std::aligned_storage<sizeof(Foo), alignof(Foo)>::type foos[20000];
for (int i = 0; i < 20000; ++i) {
new (foos + i) Foo(i);
}
The drawback seems to be that you can use only a constructor to initialize those elements, and not a free function or anything else.
Question: Can I then access those Foo's like this:
Foo* ptr = reinterpret_cast<Foo*>(foos);
ptr[50] = Foo();
What you might be looking for is std::get_temporary_buffer:
int main()
{
size_t n = 20000;
auto buf = std::get_temporary_buffer<Foo>(n);
if (buf.second<n) {
std::cerr << "Couldn't allocate enough memory\n";
return EXIT_FAILURE;
}
// ...
std::raw_storage_iterator<Foo*,Foo> iter(buf.first);
for (int i = 0; i < n; ++i) {
*iter++ = Foo();
}
// ...
std::return_temporary_buffer(buf.first);
}
Here is the deal. We have 2 different classes Class F and Class O
class F {
private:
int x;
int y;
public:
int getXf(){ return x; }
int getYf(){ return y; }
f(int ,int);
};
class O {
private:
int n;
int k;
int x;
int y;
char type;
int id;
int t;
public:
O(int ,int ,int ,int ,int);
int getX(){ return x; }
int getY(){ return y; }
};
And we have a third class P, where we initialize the values. In the class we are creating the two arrays of objects.
class Prog {
public:
int count;
int fcount;
O *o[]; //here we are declaring the arrays of objects
F *f[];
public :
//void init(); Here is the function where we initializing the values
};
Now the 2 for statements where we are creating the objects.
for(int i=0;i<10;i++){
randx = rand() % 10;
randy = rand() % 20;
o[i] = new O(100,50,i,randx,randy);
}
for(int i=0;i<3;i++){
randx = rand() % 10;
randy = rand() % 10;
f[i] = new F(randx, randy);
}
When we are printing all of the objects are here but the first 3 of the first class are replaced by the objects of the seconds. Exactly the 100 and 50 (1st for) from randx and randy (2nd for) respectively.
O *o[];
This declares an array of unknown size, which is an incomplete type. C++ doesn't allow that to be used as a class member, although some compilers will allow it as an extension, interpreting it as an array of zero size. In either case, it's not what you want.
If you know the array bound at compile time, then you should specify it:
O *o[10];
otherwise, you'll need to dynamically allocate an array at run time:
std::vector<O*> o;
for(int i=0;i<10;i++){
randx = rand() % 10;
randy = rand() % 20;
o.push_back(new O(100,50,i,randx,randy));
}
I would also suggest storing objects, or possibly smart pointers, rather than raw pointers in the array. If you really do want raw pointers for some reason, then remember to delete the objects once you've finished with them since that won't happen automatically, and don't forget the Rule of Three.
You are declaring arrays, but you never allocate memory for them. What you are seeing is just how your code is walking all over the stack.
Something more appropriate:
struct X {}; struct Y {};
class P {
public:
P() : xs(new X*[10]), ys(new Y*[10]) { init(); }
~P() {
// delete all objects
for(std::size_t i = 0; i < 10; ++i)
delete xs[i];
for(std::size_t i = 0; i < 10; ++i)
delete ys[i];
delete[] xs;
delete[] ys;
}
private:
void init() {
// initialize
for(std::size_t i = 0; i < 10; ++i)
xs[i] = new X();
for(std::size_t i = 0; i < 10; ++i)
ys[i] = new Y();
}
// prevent assignment and copy
P& operator=(const P& other);
P(const P&);
X** xs;
Y** ys;
};
Of course, all this magic becomes unnecessary if you just use
std::vector to store your data.
The problem is due to the way you declare your arrays:
O *o[/*No size here*/];
F *f[/*No size here*/];
Since you do not state the size of the arrays, this is equivalent to
O **o;
F **f;
Hence, you are declaring two members of types "pointer to pointer to O" and "pointer to pointer to F" respectively, but these are uninitialized and you have not allocated any memory for them to point to. That is, you actually don't have any arrays, just pointers which could be used to refer to the type of array you want.
If you know at compile time what size you want to use, you should specify that size in the declaration, which will give you a properly allocated array of that size. Otherwise, consider using an std::vector.
I'm trying to create my own version of an array called a safearray, to test my knowledge of operator overloading and creating proper class's and such.
I'm encountering two errors.
SafeArray.h:11:15: error: ‘const int SafeArray::operator’ cannot be overloaded
SafeArray.h:10:10: error: with ‘int& SafeArray::operator’
My code is split between three files.
Main.cpp
#include <cstdlib>
#include <iostream>
#include "SafeArray.h"
using namespace std;
int main(int argc, char** argv) {
SafeArray a(10); // 10 integer elements
for (int i = 0; i < a.length(); i++) {
cout << i << " " << a[i] << "s" << endl; // values initialise to 0
}
cout << endl << a[1]; // Program exits here.
a[3] = 42;
cout << a[3];
a[10] = 10;
cout << a[10];
a[-1] = -1; // out-of-bounds is "safe"?
SafeArray b(20); // another array
b = a; // array assignment
for (int i = 0; i < b.length(); i++) {
cout << b[i] << endl; // values copied from a
}
return 0;
}
SafeArray.h
#ifndef SAFEARRAY_H
#define SAFEARRAY_H
class SafeArray {
public:
SafeArray(int); // int variable will be the array size
int length();
int boundsCheck(int y); // constructor will call this function
// const SafeArray operator= (const SafeArray&);
int& operator[] (int y);
const int operator [] (const int y); // you need this one too.
SafeArray &operator=(SafeArray rhs) {
std::swap(array, rhs.array);
std::swap(length_, rhs.length_);
}
SafeArray(SafeArray const &other);
~SafeArray();
private:
int length_;
int *array;
//int array[];
};
#endif /* SAFEARRAY_H */
SafeArray.cpp
#include "SafeArray.h"
#include <iostream>
SafeArray::SafeArray(int x) {
length_ = x;
array = new int[length];
for (int i = 0; i < length_; i++) {
array[i] = 0;
}
}
int SafeArray::length() {
return this->length_;
}
int SafeArray::boundsCheck(int y) {
}
int& SafeArray::operator[] (int y) {
return array[y];
}
SafeArray::~SafeArray() {
delete [] array;
}
SafeArray::SafeArray(SafeArray const &other) {
int *temp = new int[rhs.size_];
for (int i=0; i<rhs.size_; i++)
temp[i] = rhs.array[i];
std::swap(temp, array);
delete [] temp;
return *this;
}
Your class definition isn't valid. int array[] is an incomplete type, which must not appear as a (non-static) class member. Some compilers accept this as a synonym for int array[0], but zero-sized arrays are not valid in C++, either (only in C99).
In short, you cannot write your code the way you do. You need to learn about dynamic allocation and manage your own memory. Check out how std::vector is implemented.
In C++11, I might recommend a std::unique_ptr<int[]> array as a quick-fix approach, to be initialized as array(new int[x]).
Actually int array[] is valid, and may appear as a class member. The following compiles with strict C++11 conformance:
class foo
{
public:
foo() {}
int length;
int A[];
};
void ralph()
{
foo *bar = (foo *)new int[ 21 ];
bar->length = 20;
bar->A[0] = 1;
}
This is legal, and has its advantages (occasionally). Although it is not commonly used.
However, I suspect that the OP wanted something more along the lines of
class SafeArray {
public:
SafeArray(int); // int variable will be the array size
int length();
int boundsCheck(int y); // constructor will call this function
int& operator[] (int y);
const int operator [] (const int y) // you need this one too.
private:
int length_;
int *array;
};
along with
SafeArray::SafeArray(int x) {
length_ = x;
array = new int[length];
for (int i = 0; i < length_; i++) {
array[i] = 0;
}
}
As #Kerrek already pointed out, your class definition is clearly wrong (shouldn't compile).
To fix it, you want to change the definition to something like:
int *array;
Then in your default ctor you could use something like this:
SafeArray::SafeArray(unsigned size = 0)
: array(new int[size])
{
for (unsigned i=0; i<size; i++)
array[i] = 0;
}
Then, yes, you'll need to write an assignment operator. The usual way is called the copy and swap idiom. You create a copy, then swap the contents of the current one with those of the copy:
SafeArray &operator=(SafeArray rhs) {
std::swap(array, rhs.array);
std::swap(length_, rhs.length_);
}
Along with that, you'll need a copy constructor that makes a copy of the data as well:
SafeArray::SafeArray(SafeArray const &other) {
int *temp = new int[rhs.size_];
for (int i=0; i<rhs.size_; i++)
temp[i] = rhs.array[i];
std::swap(temp, array);
delete [] temp;
return *this;
}
Finally, you'll need a destructor to destroy an object and (particularly) delete the memory it holds:
SafeArray::~SafeArray() {
delete [] array;
}
Then realize that all of that is an ugly mess that will never really work well. In particular, the basic methodology is restricted to an array that's basically fixed in size. As long as you only store ints, it's fairly easy to overlook the problems, and make a dynamic array that (sort of) works. When/if you want to store some other type, however, you just about need to separate allocating memory from initializing objects in that memory, which means throwing away essentially all the code above, and replacing it with something that:
keeps track of the array size and allocation size separately
allocates memory with ::operator new, an Allocator object, or something else similar
uses placement new to initialize objects in the memory when needed.
uses explicit destructor calls to destroy the objects
uses ::operator delete to release memory
and so on. To summarize, std::vector is not a trivial piece of work.
The error message refers to these two lines:
int& operator[] (int y);
const int operator [] (const int y); // you need this one too.
Your error message says that (int y) and (const int y) are too similar to be two different overloads of the [] operator. You cannot overload on (int y) and (const int y) because the calls would all be ambiguous.
You probably meant to return a const int if your SafeArray is const, but return an int& if your SafeArray is not const. In that case, you declare the second function to apply to const SafeArray, by putting the word const after the parameter list. This is what you should write in SafeArray.h:
int& operator[] (int y);
const int operator [] (int y) const; // you need this one too.
You would then have to write both of these functions in SafeArray.cpp:
int& SafeArray::operator[] (int y) {
return array[y];
}
const int SafeArray::operator[] (int y) const { // you need this one too.
return array[y];
}