【问题标题】:Copy constructor with pointers使用指针复制构造函数
【发布时间】:2010-10-21 08:56:24
【问题描述】:

我最近发现,当我在一个类中有指针时,我需要指定一个 Copy 构造函数。

为了了解这一点,我编写了以下简单代码。它可以编译,但在执行复制构造函数时会出现运行时错误。

我试图从被复制对象的指针中复制值,但避免分配相同的地址。

那么,这里有什么问题?

    class TRY{
        public:
        TRY();
    ~TRY();
        TRY(TRY const &);

        int *pointer;

        void setPointer(int);
    };


    void TRY::setPointer(int a){
        *pointer = a;

        return;
    }


    TRY::TRY(){}


    TRY::~TRY(){}


    TRY::TRY(TRY const & copyTRY){
        int a = *copyTRY.pointer;
        *pointer = a;
    }



    int main(){

        TRY a;
        a.setPointer(5);

        TRY b = a;

        b.setPointer(8);

        cout << "Address of object a = " << &a << endl;
        cout << "Address of object b = " << &b << endl;

        cout << "Address of a.pointer = " << a.pointer << endl;
        cout << "Address of b.pointer = " << b.pointer << endl;

        cout << "Value in a.pointer = " << *a.pointer << endl;
        cout << "Value in b.pointer = " << *b.pointer << endl;

        return 0;
    }

我将把这个概念用于其他有很多指针的类,我需要将所有值从一个对象复制到另一个。此代码最初需要复制,所以我想保留复制的可能性(我不会将复制构造函数隐藏为私有)。

此外,我需要实现的真正类有大约 10 个指针,而且它可能会随着时间而改变。在 C++ 中有没有更聪明的方法来拥有一个深拷贝构造函数?...

【问题讨论】:

    标签: c++ pointers copy-constructor


    【解决方案1】:

    如果它有一个指向常规类型的指针,那么

    A::A(const A& a):
      pointer_( new int( *a.pointer_ ) )
    {
    }
    

    如果它有一个指向某个基类的指针,那么

    A::A(const &a ):
      pointer_( a.pointer_->clone() )
    {
    }
    

    克隆是prototype pattern的实现

    不要忘记删除析构函数中的指针

    A::~A()
    {
        delete pointer_;
    }
    

    修正你的例子

    TRY::TRY(TRY const & copyTRY){
        int a = *copyTRY.pointer;
        pointer = new int(a);
    }
    

    【讨论】:

      【解决方案2】:

      使用int* pointer 语句,您刚刚定义了一个指针,但尚未分配任何内存。首先,您应该通过像这样分配一些内存来使其指向正确的内存位置:int* pointer = new int。然后再次在复制构造函数中,您必须为复制的对象分配内存。另外,不要忘记在析构函数中使用 delete 来释放内存。

      我希望这个例子有帮助:

      class B
      {
      
      public:
          B();
          B(const B& b);
          ~B();
          void setVal(int val);
      
      private:
          int* m_p;
      };
      
      B::B() 
      {
          //Allocate the memory to hold an int
          m_p = new int;
      
          *m_p = 0;
      }
      
      B::B(const B& b)
      {
          //Allocate the memory first
          m_p = new int;
      
          //Then copy the value from the passed object
          *m_p = *b.m_p;
      }
      
      B::~B()
      {
      
          //Release the memory allocated
          delete m_p;
          m_p = NULL;
      }
      
      void B::setVal(int val)
      {
          *m_p = val;
      }
      

      【讨论】:

      • 在为其分配新对象之前不要忘记删除 m_p。
      • 我没有定义赋值运算符,它只是一个复制构造函数。因此无需删除 m_p。
      • 在构造函数中, m_p 最初将是未定义的,除非您明确地将其放入初始化列表中。如果你试图删除一个未定义的指针,就会发生不好的事情。
      • 为什么不呢? (我的意思是在析构函数中?)
      • 已经有析构函数,内存已经正常释放了。
      【解决方案3】:

      如果你想做一个深拷贝,你当然还必须分配新的内存来保存这些值。如果原始有一个指向 int 的指针,而您不希望副本使用相同的指针值,则必须分配新内存来保存 int,然后将值复制到那里。

      你的例子不是很清楚,它没有显示你的复制构造函数的实现,或者pointer成员是如何被初始化的。

      【讨论】:

        【解决方案4】:

        你的问题就在这里:

            *pointer = a;
        

        通常在默认构造函数中发生的所有事情都还没有发生,包括为*pointer 分配内存。

        解决方法是为整数分配内存。您可以使用malloc 和朋友或new 来实现此目的,但请确保它与您在默认构造函数中使用的方法相同,因为您只有一个析构函数,并且调用必须匹配。

        【讨论】:

          【解决方案5】:

          如果成员明智的(浅)副本没问题,那么您无需执行任何操作。如果你想要一个深拷贝,你必须为所有成员的拷贝分配新的存储空间。

          【讨论】:

            【解决方案6】:

            在编写复制构造函数时,您应该为所有成员分配内存。 在你的情况下:

            TRY::TRY(TRY const & copyTRY){
                pointer = new int(*(copyTry.pointer));
            }
            

            Operator= 有点相似,但没有内存分配。

            TRY& operator=(TRY const& otherTRY){
                  this->a  = *(otherTry.pointer)
                  return *this
            }
            

            【讨论】:

              【解决方案7】:

              我最近发现,当我 在一个类中有指针,我需要 指定一个 Copy 构造函数。

              这并不完全正确。当您的类中有指针并使用new 分配内存时,您必须担心复制构造函数。另外,不要忘记赋值运算符和析构函数。 您必须删除使用delete 分配的内存。

              它叫做Law Of The Big Three

              例子:

                ~Matrix();  //Destructor
                Matrix(const Matrix& m); //Copy constructor
                Matrix& operator= (const Matrix& m); //Assignment operator
              

              【讨论】:

                【解决方案8】:

                我最近发现,当我 在一个类中有指针,我需要 指定一个复制构造函数

                通常情况下,通过将它(和赋值运算符)声明为私有而不实现它来简单地禁用它是一个好主意。

                【讨论】:

                • 为什么?在编程中复制概念上是“禁止”的,还是因为复制可能会导致 OO 语言出现问题?
                • 它不是“禁止的”——它只是经常没有意义和/或很昂贵。
                【解决方案9】:

                通常情况下,如果您需要编写复制构造函数或赋值运算符,那么您就做错了。将复制构造函数和赋值运算符留给标准库的实现者。编写您的已可复制和可分配元素的类,您不必自己编写。

                例如,也许那个 int * 成员应该是一个 std::vector。

                如果您不能使类默认可复制/可分配,也许您可​​以通过声明但不实现私有复制构造函数和赋值运算符使其不可复制/可分配。

                只有在上述都不可行的情况下,您才应该实现自己的复制构造函数或赋值运算符。

                【讨论】:

                • OMG,请远离编程,绝对停止提供任何关于此事的建议,你显然一无所知
                【解决方案10】:

                这里是复制构造函数的例子

                class Test
                {​​​​​​​
                private:
                    int *s;
                    int size;
                public:
                    Test(int a, int b);
                    Test(const Test&t);
                    ~Test();
                    void setValue(int l);
                    void getValues();
                }​​​​​​​;
                
                
                Test::Test(int a, int b)
                {​​​​​​​
                    s = new int;
                    *s = a;
                    this->size = b;
                }​​​​​​​
                Test::Test(const Test&t) {​​​​​​​
                    s = new int;
                    *s = *(t.s);
                    this->size = t.size;
                }​​​​​​​
                void Test::setValue(int l) {​​​​​​​
                    *s = l;
                }​​​​​​​
                void Test::getValues() {​​​​​​​
                    cout << "value of s: " << *s << endl;
                    cout << "value of size: " << this->size << endl;
                }​​​​​​​
                
                
                Test::~Test() {​​​​​​​
                    cout << "memory de allocated!!!" << endl;
                    delete s;
                }​​​​​​​
                

                【讨论】:

                • 复制构造函数进行复制;它是“深”还是“浅”副本的语义取决于实现者。指针数据成员确实不需要需要或需要自定义复制构造函数,而浅拷贝确实意味着将发生未定义的行为除非它拥有所有权指针 - 所以这个答案是不准确的。许多类型只是通过指针view 对象,并且这些不需要自定义复制构造函数逻辑。想想实现spanstring_viewreference_wrapper等。
                猜你喜欢
                • 1970-01-01
                • 2016-04-13
                • 2011-02-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多