21

我最近发现,当我在一个类中有指针时,我需要指定一个 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++ 中有没有更聪明的方法来拥有一个深拷贝构造函数?...

4

10 回答 10

22

使用该语句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;
}
于 2009-04-23T13:47:38.300 回答
10

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

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

它被称为三巨头法则

例子:

  ~Matrix();  //Destructor
  Matrix(const Matrix& m); //Copy constructor
  Matrix& operator= (const Matrix& m); //Assignment operator
于 2009-04-23T14:07:46.380 回答
3

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

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

于 2009-04-23T13:48:08.033 回答
2

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

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

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

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

克隆是原型模式的实现

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

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

修复你的例子

TRY::TRY(TRY const & copyTRY){
    int a = *copyTRY.pointer;
    pointer = new int(a);
}
于 2009-04-23T13:46:37.943 回答
2

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

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

于 2009-04-23T14:08:10.090 回答
1

您的问题就在这一行:

    *pointer = a;

默认构造函数中通常发生的所有事情都还没有发生,包括为*pointer.

解决方法是为整数分配内存。您可以使用mallocand Friends 或newfor this,但请确保它与您在默认构造函数中使用的方法相同,因为您只会获得一个析构函数,并且调用必须匹配。

于 2009-04-23T13:52:16.087 回答
1

如果成员明智的(浅)副本是可以的,那么您不必做任何事情。如果你想要一个深拷贝,你必须为所有成员的拷贝分配新的存储空间。

于 2009-04-23T13:54:54.710 回答
0

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

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

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

TRY& operator=(TRY const& otherTRY){
      this->a  = *(otherTry.pointer)
      return *this
}
于 2009-04-23T14:05:27.773 回答
-1

这是复制构造函数的示例

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;
}​​​​​​​
于 2021-06-26T04:06:09.133 回答
-3

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

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

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

只有当以上都不可行时,您才应该实现自己的复制构造函数或赋值运算符。

于 2009-04-23T17:17:29.093 回答