将对象传递给C ++函数时的副作用

时间:2011-10-14 04:20:28

标签: c++ destructor side-effects deep-copy

我已在C++ : The Complete Reference中读到以下内容

  

即使通过法线将对象传递给函数   call-by-value参数传递机制,理论上可以保护   并且使调用参数绝缘,对于一方来说仍然是可能的   可能影响甚至损坏用作物体的物体   论点。例如,如果用作参数的对象分配   内存并在销毁时释放内存,然后释放其本地副本   函数内部将在其析构函数时释放相同的内存   调用。这将使原始对象受损且有效   无用的。

我真的不明白副作用是如何发生的。有人可以通过一个例子来帮助我理解这个吗?

3 个答案:

答案 0 :(得分:5)

以下是一个例子:

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;

答案 1 :(得分:1)

那篇文章可能正在谈论这种情况:

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
}

答案 2 :(得分:0)

这是另一个例子。关键是当调用callee(SomeFunc)参数析构函数时,它将释放调用者参数(obj1)指向的同一个对象(ptr)。因此,在调用之后对调用者参数(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();
}