Странични ефекти при предаване на обекти за функциониране в 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


Отговори (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

Ето още един пример. Въпросът е, че когато деструкторът на параметъра callee (SomeFunc) бъде извикан, той ще освободи същия обект (ptr), към който сочи аргументът на caller (obj1). Следователно всяко използване на аргумента на повикващия (obj1) след извикването ще доведе до segfault.

#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