为什么我无法在for循环中访问动态分配的内存?

时间:2015-02-26 21:23:50

标签: c++ pointers polymorphism

我为我的子类类型库存新建了一个内存,它继承自基类工具,当我尝试访问我的数组的第二个元素时,它会抛出错误。当我的新数组大小为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;

} 

3 个答案:

答案 0 :(得分:7)

多态性和指针算法不会混合,因为数组中对象的排列取决于最大的派生大小,而多态性会丢失该信息。动态分配是一个红色的鲱鱼,你可以看到同样的问题:

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

请注意,使用array的指针值向前移动sizeof (Derived),但使用p的指针算法向前移动sizeof (Base)而未找到真实对象。< / p>

通常,您可以使用Base*数组来修复此问题,而不是将单个Base*与指针算法结合使用。

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

另一种选择是使用记住原始类型的对象:

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

并使用poly(i)代替p[i]

但是警告,你不能delete [] &poly(0);,因为delete[]也不是多态的。

使用std::unique_ptr<Derived[]>std::bind,当访问者对象最终超出范围时,可以安排自动释放。

答案 1 :(得分:1)

虽然Mr.Ben的方法是绝对正确的,但我完全觉得他的C ++和我的C ++不是同一种语言,他在这里混合了一些奇怪的东西,因此根据他的想法,我试图像这样修改我的代码

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

}

答案 2 :(得分:0)

tl;博士回答:不要将子类数组(Stock[N])转换为基类指针(pBase)。直接使用Stock*,或者创建一个指针数组:

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

详细原因:

1)数组括号运算符是一个语法糖:a[b] -> *(a + b);

2)指针算法不是多态的,它总是基于静态类型:

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

3)然而,这是你想要的:

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

4)只要sizeof(Instrument) != sizeof(Stock),你就遇到了麻烦。