Why can't I access dynamically allocated memory in my for loop?

I create new memory for my child class, which inherits from the base class tool, when I try to access the second element of my array, it throws an error. Everything is fine when I have a new array size 1

#include <iostream> #include <fstream> #include <string> using namespace std; class Instrument{ public: virtual void display(){} virtual void output(){} virtual void readFile(){} virtual ~Instrument(){} }; class Stock : public Instrument{ public: Stock(){ } virtual void input(){ cout << "This is stock, please input its information: "; cin >> name >> bidPrice >> askPrice >> lastPrice >> issueExchange; } virtual void display(){ cout <<"This is to display stock: "<< name << " " << bidPrice << " " << askPrice << " " << lastPrice << " " << issueExchange << " " << endl; } virtual void output(){ ofstream myfile; myfile.open("Stock.txt", ios::out | ios::app); if (myfile.is_open()){ myfile << "This is a stock: " << name << " " << bidPrice << " " << askPrice << " " << lastPrice << " " << issueExchange << " " << endl; } else cout << "Unable to open file"; } virtual void readFile(){ string line; ifstream myfile("Stock.txt"); cout << "\nThis is file stored\n"; if (myfile.is_open()) { while (getline(myfile, line)) { cout << line << '\n'; } myfile.close(); } } virtual ~Stock(){} private: char name[13]; double bidPrice; double askPrice; double lastPrice; int issueExchange; }; int main(){ const int N = 5;//it works fine if I use N=1; Instrument *pBase = NULL; pBase = new Stock[N]; for (int i = 0; i < N; i++){ pBase[i].input();// here throws an exception and ends the program pBase[i].display(); pBase[i].output(); } pBase[N - 1].readFile(); delete[] pBase; system("pause"); return 0; } 
+6
source share
3 answers

Polymorphism and arithmetic of pointers do not mix, since the location of objects inside the array depends on the derived size itself, and polymorphism loses this information. Dynamic allocation is a red herring, you can see the same problem:

 Derived array[2]; Base* p = array; printf("%p\n", &array[0]); printf("%p\n", p); printf("%p\n", &array[1]); printf("%p\n", p + 1); printf("%z\n", sizeof (array[0])); printf("%z\n", sizeof (*p)); 

Note that the pointer values ​​are moved forward by sizeof (Derived) using array , but pointer arithmetic using p moves forward sizeof (Base) and cannot find real objects.

You usually fix this with a Base* array instead of a single Base* in combination with pointer arithmetic.

 Base* pp[2]; for( auto& elem : array ) pp[&elem - array] = &elem; printf("%p\n", &array[1]); printf("%p\n", pp[1]); // use (*pp[1]) or pp[1]->whatever 

Another option is to use an object that remembers the original type:

 Derived* allocated = new Derived[N]; std::function<Base& (int)> poly = [allocated](int i){ return allocated[i]; }; 

and use poly(i) instead of p[i]

But a warning, you CANNOT do delete [] &poly(0); , because delete[] also not polymorphic.

Using std::unique_ptr<Derived[]> and std::bind , you can arrange for automatic release when the accessory object finally goes out of scope.

+7
source

Although Mr.Ben's method is absolutely right, but I completely feel that its C ++ and my C ++ are not the same language, it mixes some strange things here, so according to his idea, I tried to change my code, like this.

 #include <iostream> #include <fstream> #include <string> #include <vector> #include <memory> using namespace std; class Instrument{ public: virtual void display() = 0; virtual void output() = 0; virtual void readFile() = 0; virtual ~Instrument(){}; }; class Stock : public Instrument{ public: Stock(){ cout << "This is stock, please input its information: "; cin >> name >> bidPrice >> askPrice >> lastPrice >> issueExchange; } virtual void display(){ cout << "This is to display stock: " << name << " " << bidPrice << " " << askPrice << " " << lastPrice << " " << issueExchange << " " << endl; } virtual void output(){ ofstream myfile; myfile.open("Stock.txt", ios::out | ios::app); if (myfile.is_open()){ myfile << "This is a stock: " << name << " " << bidPrice << " " << askPrice << " " << lastPrice << " " << issueExchange << " " << endl; } else cout << "Unable to open file"; } virtual void readFile(){ string line; ifstream myfile("Stock.txt"); cout << "\nThis is file stored\n"; if (myfile.is_open()) { while (getline(myfile, line)) { cout << line << '\n'; } myfile.close(); } } virtual ~Stock(){} private: string name; double bidPrice; double askPrice; double lastPrice; int issueExchange; }; class Option : public Instrument{ public: Option(){ cout << "This is option, please input its information: "; cin >> name >> uname >> bidPrice >> askPrice >> lastPrice >> contractSize >> exp; } virtual void display(){ cout << "This is to display option: " << name << " " << uname << " " << bidPrice << " " << askPrice << " " << lastPrice << " " << contractSize << " " << exp << " " << endl; } virtual void output(){ ofstream myfile; myfile.open("Option.txt", ios::out | ios::app); if (myfile.is_open()){ myfile << "This is an option: " << name << " " << uname << " " << bidPrice << " " << askPrice << " " << lastPrice << " " << contractSize << " " << exp << " " << endl; } else cout << "Unable to open file"; } virtual void readFile(){ string line; ifstream myfile("Option.txt"); cout << "\nThis is file stored\n"; if (myfile.is_open()) { while (getline(myfile, line)) { cout << line << '\n'; } myfile.close(); } } virtual ~Option(){} private: string name; string uname; double bidPrice; double askPrice; double lastPrice; int contractSize; double exp; }; class Future : public Instrument{ public: Future(){ cout << "This is option, please input its information: "; cin >> name >> uname >> bidPrice >> askPrice >> lastPrice >> contractSize >> tickSize >> contractMonth; } virtual void display(){ cout << "This is to display option: " << name << " " << uname << " " << bidPrice << " " << askPrice << " " << lastPrice << " " << contractSize << " " << tickSize << " " << contractMonth << " " << endl; } virtual void output(){ ofstream myfile; myfile.open("Future.txt", ios::out | ios::app); if (myfile.is_open()){ myfile << "This is a future: " << name << " " << uname << " " << bidPrice << " " << askPrice << " " << lastPrice << " " << contractSize << " " << tickSize << " " << contractMonth << " " << endl; } else cout << "Unable to open file"; } virtual void readFile(){ string line; ifstream myfile("Future.txt"); cout << "\nThis is file stored\n"; if (myfile.is_open()) { while (getline(myfile, line)) { cout << line << '\n'; } myfile.close(); } } virtual ~Future(){} private: string name; string uname; double bidPrice; double askPrice; double lastPrice; int contractSize; int tickSize; int contractMonth; }; int main(){ int N = 20; //shared_ptr<Instrument> pBase[N]; vector<shared_ptr<Instrument>> pBase(N); int i = 5; for (i = 0; i < N; i++) pBase[i] = make_shared<Stock>(); for (i = 0; i < N; i++){ pBase[i]->display(); pBase[i]->output(); } pBase[N - 1]->readFile(); for (i = 0; i < N; i++) pBase[i] = make_shared<Option>(); for (i = 0; i < N; i++){ pBase[i]->display(); pBase[i]->output(); } pBase[N - 1]->readFile(); for (i = 0; i < N; i++) pBase[i] = make_shared<Future>(); for (i = 0; i < N; i++){ pBase[i]->display(); pBase[i]->output(); } pBase[N - 1]->readFile(); system("pause"); return 0; } 
+1
source

tl; dr answer: do not convert the array of the subclass ( Stock[N] ) to a pointer to the base class ( pBase ). Either use Stock* , or create an array of pointers instead:

 auto arr = new Stock*[N]; for (int i = 0; i < N; i++) { arr[i] = new Stock(); } // unrelated but suggested: C++11 unique_ptr is recommended: vector<unique_ptr<Stock>> v(N); 

Detailed reasons:

1) The array bracket operator is syntactic sugar: a[b] -> *(a + b) ;

2) Pointer arithmetic is not polymorphic; it is always based on static types:

 pBase[i] -> *(pBase+i) -> *(pBase*)((char*)pBase + sizeof(Instrument) * i); 

3) This, however, is what you want:

 pBase[i] -> *(pBase+i) -> *(pBase*)((char*)pBase + sizeof(Stock) * i); 

4) As long as sizeof(Instrument) != sizeof(Stock) , you have problems.

0
source

Source: https://habr.com/ru/post/983065/


All Articles