В C ++ не разрешено передавать объект в функцию напрямую? - PullRequest
0 голосов
/ 19 октября 2011

Я знаю C, но я плохо разбираюсь в C ++.

Следующий код завершится сбоем (в getval () использование ссылки в качестве параметра допустимо).И значение *p изменяется после первого оператора cout.Похоже, что произошла некоторая перезапись из-за нехватки памяти.

Мой вопрос: почему произошел сбой (или почему его значение изменилось).Это «вызов по значению» объекта, так должно ли оно работать в любом случае?

class myclass { 
  int *p; 

  public: 
    myclass(int i); 
    ~myclass() { delete p; } 
    int getval(myclass o); 
}; 

myclass::myclass(int i) 
{ 
  p = new int; 

  if (!p) { 
    cout << "Allocation error\n"; 
    exit(1); 
  } 

  *p = i; 
}

int myclass::getval(myclass o) 
{ 
  return *o.p; 
} 

int main() 
{ 
  myclass a(1), b(2); 

  cout << a.getval(a) << " " << a.getval(b) << endl; 
  cout << b.getval(a) << " " << b.getval(b) << endl; 

  return 0; 
} 

Ответы [ 6 ]

6 голосов
/ 19 октября 2011

Прочтите правило трех .

По сути, ваш код не поддерживает копирование по значению.

Таким образом, динамически выделяемая памятьпреждевременно освобожден (деструктором).

Приветствия & hth.,

3 голосов
/ 19 октября 2011

У меня вопрос, почему он разбился (или почему его значение изменилось).

Это очень распространенная проблема мелкого копирования и двойного удаления . Компилятор выбирает конструктор копирования по умолчанию, и a.p и o.p указывают на одну и ту же область памяти. Когда оба объекта вызывают свой деструктор, оператор delete p; выполняется дважды . Многократное освобождение одной и той же памяти является неопределенным поведением , что приводит к сбою в вашей системе.

Это «вызов по значению» объекта, так должно ли оно работать в любом случае?

Если правильно закодировать, то да будет работать. Сделайте глубокую копию содержимого p, и тогда оно должно работать. Тем не менее, лучше перейти по ссылке, пока это возможно.

2 голосов
/ 19 октября 2011

То, что вы делаете, разрешено в отношении языка C ++. Но это действительно очень плохое программирование. Он не хочет комментировать каждую строку вашего кода. Вместо этого я переписываю весь код, а вы сравниваете этот код с вашим, а также видите комментарии, встроенные в код:

class myclass { 
  int p;  //no pointer, as it is not needed

  public: 
    myclass(int i) : p(i) {} //use member initialization-list 
    int getval() const  //no parameter, and make the function const
    {
         return p;
    }
}; 

int main() 
{ 
  myclass a(1), b(2); 

  cout << a.getval() << endl;
  cout << b.getval() << endl; 
  return 0; 
} 
1 голос
/ 19 октября 2011

Вы передаете myclass в качестве значения, поэтому копия создана.Когда myclass :: getval возвращает стек, развернутый и вызывается деструктор myclass, освобождая память, на которую указывает указатель в другом объекте.

0 голосов
/ 19 октября 2011

Вы не реализовали конструктор копирования (если это так, имейте в виду правило трех), поэтому, когда копии уничтожаются, вы освобождаете одну и ту же память несколько раз.

Подсказки:

Реализация конструктора копирования:

myclass(const myclass& other)
{
   p = new int;
   *p = *other.p;
}

Передача по ссылке:

int getval(const myclass& o); 

Хорошее правило также состоит в том, чтобы сделать функции, которые не зависят от самого объекта, статическими (это не поможет вам в этом конкретном случае, но тем не менее полезно).Поскольку getval не имеет доступа к элементам объекта, вы можете сделать его статическим.

Причины сбоя:

При вызове getval(o) создается копия oи его член указывает на то же место, что и исходный объект, так как вы не объявили конструктор копирования.Копия уничтожена, а память удалена.Исходный объект поврежден.

0 голосов
/ 19 октября 2011

Вы дважды удаляете p здесь, общий указатель может быть полезен, если вы не хотите делать глубокую копию.Пока это возможно и имеет смысл, попробуйте вместо этого использовать автоматические переменные (int вместо int *)

...