【问题标题】:Side effects when passing objects to function in C++将对象传递给 C++ 中的函数时的副作用
【发布时间】:2011-12-07 11:00:47
【问题描述】:

我在C++ : The Complete Reference 中阅读了以下内容

即使对象是通过普通的方式传递给函数的 按值调用的参数传递机制,理论上可以保护 并隔离调用参数,它仍然是可能的一方 发生可能影响甚至损坏用作对象的对象的效果 争论。例如,如果用作参数的对象分配 内存并在销毁时释放该内存,然后释放其本地副本 当函数的析构函数为 叫。这将使原始对象损坏并有效 没用。

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

【问题讨论】:

  • 这不是副作用,是写得不好的类型。
  • 那本书是由有史以来最糟糕的 C++ 作者之一写的。你最好现在处理掉它。将其放入垃圾桶并点亮。以后你会感谢我的。
  • @FredOverflow,对于懂C编程,对C++有一点了解,想快速学习C++并开始编码的人,你推荐哪本书

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


【解决方案1】:

这是一个例子:

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 用作参数的变量指向的资源。请注意,在进行 any 复制构造时会发生同样的事情:

bad_design first( 512 );
bad_design error( first );
bad_design error_as_well = first;

【讨论】:

    【解决方案2】:

    那一段大概是在说这种情况:

    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
    }
    

    【讨论】:

      【解决方案3】:

      这是另一个例子。关键是,当调用被调用者 (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();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-27
        • 2015-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-01
        • 1970-01-01
        • 2012-10-31
        相关资源
        最近更新 更多