У меня есть проблемные элементы адресации внутри объектов Class3, пожалуйста, посмотрите на эти упрощенные классы:
class Class1 {
public:
std::vector<Class2> c2v;
Class1();
};
class Class2 {
Class1 *instance;
int id;
public:
std::vector<Class3> c3v;
Class2 ( Class1 *instance, int id );
};
class Class3 {
Class1 *instance;
int id;
public:
Class3 ( Class1 *instance, int id );
};
И их конструкторы:
Class1::Class1()
{
for ( int i = 0; i < noi; ++i ) {
c2v.push_back ( Class2 ( this, i ) );
}
}
Class2::Class2 ( Class1 *instance, int id )
{
this->instance = instance;
this->id = id;
for ( int k = 0; k < nok; ++k ) {
c3v.push_back ( Class3 ( this->instance, k ) );
}
}
В main () объект Class1 создается с помощью конструктора по умолчанию. Поэтому он создает вектор c2v и заполняет его объектами noi класса 2.
В то же время, когда объекты Class2 помещаются в вектор c2v, они создаются, и каждый из них создает вектор c3v и заполняет его «не» объектами Class3.
Код компилируется нормально, но во время выполнения при доступе к публичным атрибутам Class2 из объектов Class3 (через this->instance->c2v[0].getSomeAttribute()
) программа останавливается с EXC_BAD_ACCESS.
Проверка с помощью отладчика показывает, что указатель на c2v[0]
поврежден (его значение становится 0x0).
Я новичок в C ++. Мне было интересно, что это за ошибка при попытке создания экземпляров векторов таким образом. Должен ли я только объявлять векторы и заполнять их в отдельной функции, вызываемой после завершения создания всех экземпляров Class2 и Class3?
Я добавляю некоторый фактический код, надеюсь, что его чтение не займет много времени (пожалуйста, поймите, я пропустил некоторые предварительные объявления и директивы препроцессора):
// global variables
extern char *filename; //not used
extern int nodes;
extern int numProdotti;
extern int classe; //not used
extern int maxNumRange; //not used
extern int *numRanges;
extern int *list ;
extern int *typeProdMarket;
extern int totalQtyDemand; //not used
extern int totNumRanges; //not used
extern struct product {
int qty;
int cost;
} **prodMarket;
extern struct range {
int discount;
int startOfRange;
} **rangeMarket; //not used
int main ( int argc, char *argv[] )
{
Ctqd instance;
instance.runOpt();
}
class Ctqd {
void greedySimple();
void greedySimpleReverse();
void greedyFromY();
void greedyByNiceness1();
void greedyByNiceness2();
void greedyByStepTier1();
void greedyByStepTier2();
void randomLocalSearch1();
void LocalSearch2opt();
public:
std::vector<Item> items;
std::vector<Supplier> suppliers;
Solution *solution;
Ctqd();
~Ctqd();
void runOpt();
};
class Supplier {
Ctqd *instance;
int id;
int refTotQty;
int refDiscount;
int refDiscountTier;
double refTotPrice;
double refUnitPrice;
double niceness;
int purTotQty;
int purDiscount;
int purDiscountTier;
public:
std::vector<Offer> offers;
Supplier ( Ctqd *instance, int id );
int getId();
int getRefTotQty();
int getRefDiscount();
int getRefDiscountTier();
double getRefTotPrice();
double getRefUnitPrice();
double getNiceness();
int getPurTotQty();
int getPurDiscount();
int getPurDiscountTier();
void updateStats();
};
class Offer {
Supplier *supplier;
int id;
int refQty;
double refPrice;
double niceness;
int purQty;
public:
Offer ( Supplier *supplier, int id );
int getId();
int getRefQty();
double getRefPrice();
double getNiceness();
int getPurQty();
void setPurQty ( int qty );
int remainingQty();
};
Ctqd::Ctqd()
{
// constructing items vector
for ( int k = 0; k < numProdotti; ++k ) {
items.push_back ( Item ( this, k ) );
}
// constructing suppliers vector
for ( int i = 0; i < nodes; ++i ) {
suppliers.push_back ( Supplier ( this, i ) );
}
// building solution
solution = new Solution ( this );
}
Supplier::Supplier ( Ctqd *instance, int id )
{
this->instance = instance;
this->id = id;
// computing total reference quantity
refTotQty = 0;
for ( int k = 0; k < numProdotti ; ++k ) {
refTotQty += std::min ( list[ k ] , prodMarket[ this->id ][ k ].qty );
}
// computing reference discount coefficients
refDiscount = 0;
refDiscountTier = 0;
for ( int r = 0; r < numRanges[ this->id ]; ++r ) {
if ( refTotQty < rangeMarket[ this->id ][ r ].startOfRange ) {
break;
}
else {
refDiscount = rangeMarket[ this->id ][ r ].discount;
refDiscountTier = r;
}
}
//computing total reference price
refTotPrice = 0;
for ( int k = 0; k < numProdotti ; ++k ) {
refTotPrice += prodMarket[ this->id ][ k ].cost * std::min ( list[ k ] , prodMarket[ this->id ][ k ].qty );
}
refTotPrice = refTotPrice * ( 1.000 - refDiscount / 100.000 );
//computing reference unit price
refUnitPrice = refTotPrice / refTotQty;
//computing supplier niceness
niceness = refTotQty / refUnitPrice;
purTotQty = 0;
purDiscount = 0;
purDiscountTier = 0;
// building offers vector
for ( int k = 0; k < numProdotti; ++k ) {
offers.push_back ( Offer ( this, k ) );
}
}
Offer::Offer ( Supplier *supplier, int id )
{
this->supplier = supplier;
this->id = id;
// computing reference quantity
refQty = std::min ( list[ this->id ] , prodMarket[ this->supplier->getId() ][ this->id ].qty );
// computing reference price
refPrice = prodMarket[ this->supplier->getId() ][ this->id ].cost * ( 1.000 - this->supplier->getRefDiscount() / 100.000 );
// computing niceness of the offer
niceness = refQty / ( ( prodMarket[ this->supplier->getId() ][ this->id ].cost + refPrice ) / 2 );
// init purQty to 0
purQty = 0;
}
Вот где я получаю EXC_BAD_ACCESS:
int Offer::remainingQty()
{
return prodMarket[ supplier->getId() ][ id ].qty - purQty;
}
Я провел несколько экспериментов:
Изменены векторы в классе Ctqd и в классе Supplier на векторы указателей на объекты.
Проблема была решена только частично.
Все еще имел EXC_BAD_ACCESS при создании объектов предложений.
Для конструктора класса Offer нужны данные из объекта Supplier, который его создал.
Я думал, что доступ к этим данным, когда вектор поставщиков еще заполнен, может привести к проблемам, поэтому я создал небольшую функцию initialize () в поставщике:
void Supplier::initialize()
{
// constructing offers vector
for ( int k = 0; k < numProdotti; ++k ) {
offers.push_back ( new Offer ( this->instance, id, k ) );
}
}
И добавил это в конце конструктора класса Ctqd:
// init newly built objects
for ( int i = 0; i < nodes; ++i ) {
suppliers[i]->initialize();
}
Теперь все работает нормально. Но я так и не понял, в чем конкретно проблема.