C ++类复制(指针复制)

时间:2011-02-17 18:51:54

标签: c++ class pointers

我的理解是,当您复制定义指针变量的类时,会复制指针,但指针指向的数据不会复制。

我的问题是:是否假设在这种情况下“指针复制”只是实例化相同类型的新指针(动态内存分配)?例如,新指针只是一个包含任意内存地址的新分配,应该注意将新指针指向适当的内存地址吗?

我认为对这个问题有一个非常简单的答案,我为其微不足道的性质道歉,但我试图在更深层次上理解指针,这是我在互联网上研究的指针。

此致

乍得

5 个答案:

答案 0 :(得分:18)

指针将被简单地复制为一个值 - 因此两个类都将指向相同的原始内存,不会发生新的分配。 浅拷贝 - 这是默认语言的作用。

如果您需要分配新内存并复制数据,则必须在复制构造函数中自行完成。 深层复制 - 您必须自己执行此操作

编辑:这是C ++的优点之一,您可以自由决定复制的工作原理。可能是仅对存储器进行读访问的对象的副本可以避免复制存储器的成本。如果新对象需要写入,您还可以实现只生成原始数据副本的类。

答案 1 :(得分:8)

首先,类中的指针是静态的(即编译器知道此类中有一个指针及其大小,因此在实例化类时不需要动态内存分配)。

如果复制类(并且没有定义特殊的复制构造函数),则新类中的指针将指向内存中与旧类中的指针相同的位置。澄清:

#include <iostream>

class A {
   public:
       int *p;
};

int main() {
    A a,b;
    a.p = new int(10);
    b = a;

    std::cout << "*(a.p) = " << *(a.p) << std::endl; // 10
    std::cout << "*(b.p) = " << *(b.p) << std::endl; // 10

    *(b.p) = 3;

    std::cout << "*(a.p) = " << *(a.p) << std::endl; // 3
    std::cout << "*(b.p) = " << *(b.p) << std::endl; // 3

    return 0;
}

现在,如果要在复制时分配新内存,则需要编写复制构造函数和复制赋值构造函数:

#include <iostream>

class A {
   public:
       int *p;

       A() : p(0) {}
       A(const A& other) { // copy constructor
           p = new int(*other.p);
       }

       A& operator=(const A& other) { // copy assignment constructor
           // protect against self assignment
           if (this != &other) {
               if (p != 0) {
                   *p = *other.p;
               } else { // p is null - no memory allocated yet
                   p = new int(*other.p);
               }
           }
           return *this;
       }

       ~A() { // destructor
           delete p;
       }
};


int main() {
    A a,b;
    a.p = new int(10);
    b = a;

    std::cout << "*(a.p) = " << *(a.p) << std::endl; // 10
    std::cout << "*(b.p) = " << *(b.p) << std::endl; // 10

    *(b.p) = 3;

    std::cout << "*(a.p) = " << *(a.p) << std::endl; // 10
    std::cout << "*(b.p) = " << *(b.p) << std::endl; // 3

    return 0;
}

执行此操作时,还应编写析构函数(请参阅Rule of three),因为如果类被销毁,则需要在复制/复制赋值构造函数中分配的内存:

答案 2 :(得分:3)

指针不实例化动态内存分配。指针和分配完全不同。

如果复制指向动态分配内存的指针,则有两个指针指向相同的已分配内存。由于您已将其复制,因此它已指向内存块。具体来说,如果使用编译器生成的复制构造函数,新指针将指向与旧指针完全相同的东西。如果可以的话,你不需要对它做任何事情。

你确实有什么时候释放内存的问题。释放它两次通常会导致堆损坏,这是令人讨厌的。不释放它会导致内存泄漏,这在某些情况下是可以接受的。在另一个指针通过它之前释放它也会导致问题。出于这个原因,拥有多个指向同一内存的人经常会访问Boost项目并使用他们的shared_ptr模板(这将在即将推出的新标准中,并且存在于大多数最新系统中)。

如果希望每个指针指向单独的内存块,则必须通过编写自己的复制构造函数,并分配新的块并在其中复制必要的数据来进行设置。 (你也需要编写自己的赋值运算符,出于完全相同的原因,以及你自己的析构函数,这样你就可以释放内存。有一个经验法则,称为Rule of Three,它说你是否需要编写自己的副本构造函数,赋值运算符或析构函数,您可能需要编写所有这些函数。)

答案 3 :(得分:2)

复制的指针将指向完全相同的地址。没有新的分配。

答案 4 :(得分:1)

是的,指针只包含内存地址,如果你想在拷贝构造函数中制作更深层的副本,你需要自己编写代码。

如果您总是通过来自同一类的指针引用相同类型的数据,并且需要将数据与对象一起复制,您还可以考虑将其设置为普通成员,而不是指针。