Побочные эффекты при передаче объектов в функции на C++

Я прочитал в C++ : The Complete Reference книге следующее

Несмотря на то, что объекты передаются функциям с помощью обычного механизма передачи параметров вызова по значению, который теоретически защищает и изолирует вызывающий аргумент, по-прежнему возможен побочный эффект, который может повлиять или даже повредить , объект, используемый в качестве аргумента. Например, если объект, используемый в качестве аргумента, выделяет память и освобождает эту память при уничтожении, то его локальная копия внутри функции освободит ту же память при вызове его деструктора. Это оставит исходный объект поврежденным и фактически бесполезным.

Я не очень понимаю, как возникает побочный эффект. Может ли кто-нибудь помочь мне понять это на примере?


person nitin_cherian    schedule 14.10.2011    source источник
comment
Это не побочный эффект, это плохо написанный шрифт.   -  person Cat Plus Plus    schedule 14.10.2011
comment
Эта конкретная книга написана одним из худших авторов C++. Вам лучше избавиться от него сейчас. Положите его в мусорное ведро и зажгите. Ты поблагодаришь меня позже.   -  person fredoverflow    schedule 14.10.2011
comment
@FredOverflow, какую книгу вы порекомендуете человеку, который знаком с программированием на C, немного знаком с C++ и хочет быстро изучить C++ и начать кодирование   -  person nitin_cherian    schedule 14.10.2011
comment
Полное руководство и список книг по C++   -  person fredoverflow    schedule 14.10.2011


Ответы (3)


Этот отрывок, вероятно, говорит об этой ситуации:

class A {
  int *p;
public:
  A () : p(new int[100]) {}
  // default copy constructor and assignment
 ~A() { delete[] p; }
};

Теперь объект A используется как передача по значению:

void bar(A copy)
{
  // do something
  // copy.~A() called which deallocates copy.p
}
void foo ()
{
  A a;  // a.p is allocated
  bar(a);  // a.p was shallow copied and deallocated at the end of  'bar()'
  // again a.~A() is called and a.p is deallocated ... undefined behavior
}
person iammilind    schedule 14.10.2011

Вот пример:

class bad_design
{
public:
    bad_design( std::size_t size )
      : _buffer( new char[ size ] )
    {}

    ~bad_design()
    {
        delete[] _buffer;
    }

private:
    char* _buffer;
};

Обратите внимание, что у класса есть конструктор и деструктор для обработки ресурса _buffer. Ему также потребуется правильный конструктор копирования и оператор присваивания, но это настолько плохой дизайн, что его не добавили. Компилятор заполнит их реализацией по умолчанию, которая просто копирует указатель _buffer.

При вызове функции:

void f( bad_design havoc ){ ... }

вызывается конструктор копирования bad_design, который создаст новый объект, указывающий на тот же буфер, что и переданный в качестве аргумента. Когда функция вернется, будет вызван локальный деструктор копии, который будет delete использовать ресурсы, на которые указывает переменная, используемая в качестве аргумента. Обратите внимание, что то же самое происходит при создании любой копии:

bad_design first( 512 );
bad_design error( first );
bad_design error_as_well = first;
person K-ballo    schedule 14.10.2011

Вот еще один пример. Дело в том, что при вызове деструктора параметра вызываемого объекта (SomeFunc) он освобождает тот же объект (ptr), на который указывает аргумент вызывающего объекта (obj1). Следовательно, любое использование аргумента вызывающей стороны (obj1) после вызова вызовет ошибку сегментации.

#include <iostream>
using namespace std;

class Foo {
public:
    int *ptr;

    Foo (int i) {
        ptr = new int(i);
    }

    ~Foo() {
        cout << "Destructor called.\n" << endl;
        //delete ptr;
    }

    int PrintVal() {
        cout << *ptr;
        return *ptr;
    }
};

void SomeFunc(Foo obj2) {
    int x = obj2.PrintVal();
} // here obj2 destructor will be invoked and it will free the "ptr" pointer.

int main() {
    Foo obj1 = 15;

    SomeFunc(obj1);

    // at this point the "ptr" pointer is already gone.
    obj1.PrintVal();
}
person JohnTortugo    schedule 11.12.2014