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

nit*_*ian 5 c++ destructor side-effects deep-copy

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

即使通过普通的按值调用参数传递机制将对象传递给函数,理论上它们可以保护和隔离调用参数,但是仍然可能发生可能影响甚至损坏的副作用,用作参数的对象.例如,如果用作参数的对象分配内存并在销毁时释放该内存,那么在调用析构函数时,函数内部的本地副本将释放相同的内存.这将使原始物体损坏并且实际上无用.

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

K-b*_*llo 5

这是一个例子:

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

    ~bad_design()
    {
        delete[] _buffer;
    }

private:
    char* _buffer;
};
Run Code Online (Sandbox Code Playgroud)

请注意,该类具有构造函数和析构函数来处理_buffer资源.它还需要一个合适的复制构造函数和赋值运算符,但这是一个糟糕的设计,它没有被添加.编译器将填充那些只复制指针的默认实现_buffer.

调用函数时:

void f( bad_design havoc ){ ... }
Run Code Online (Sandbox Code Playgroud)

bad_design调用的复制构造函数,它将创建一个指向与作为参数传递的缓冲区相同的缓冲区的新对象.当函数返回时,将调用本地拷贝析构函数,该函数将delete变量指向的资源用作参数.请注意,执行任何复制构造时会发生同样的事情:

bad_design first( 512 );
bad_design error( first );
bad_design error_as_well = first;
Run Code Online (Sandbox Code Playgroud)


iam*_*ind 1

那段话大概是在说这样的情况:

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

现在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
}
Run Code Online (Sandbox Code Playgroud)