具有动态分配数组的类的C ++复制构造函数

时间:2014-06-15 08:45:42

标签: c++ arrays copy-constructor dynamic-allocation

刚开始使用C ++(现在几天),我来自C背景。

我有一个类,主要包含一个指向int数组的指针,代码如下:

class Array
{
private:
    int * _arr;
    int _size;
public:
    Array();
    Array(int size);
    Array(const Array& obj);  // copy constructor
    ~Array();
    void readInValues();
    void mult(int num);
    void add(int num);
    void printArray();
};

_arr是一个指向int数组的指针,当使用复制构造函数创建一个新实例时,我会在堆上创建一个新的int数组(我认为)。在复制构造函数中:

Array::Array( const Array & obj )
{
    _arr = new int[_size];

    for(int i=0;i<_size;i++)
        *_arr[i] = *obj._arr[i];
}

我做的第一件事就是为新数组分配内存(_size是一种原始类型,因此据我所知自动复制)。我想做的下一件事是使用循环复制数组本身。这部分未通过编译说非法间接。我不知道为什么......

5 个答案:

答案 0 :(得分:4)

此:

Array::Array( const Array & obj )
{
    _arr = new int[_size];

    for(int i=0;i<_size;i++)
        *_arr[i] = *obj._arr[i];
}

可能是这样的:

Array::Array( const Array & obj )
    : _arr(obj._size ? new int[obj._size] : nullptr)
    , _size(obj._size)
{
    if (_arr)
        std::copy(obj._arr, obj._arr+_size, _arr);
}

具体来说,请注意初始化列表的使用。其他值得一提的事情:

  1. 不要使用带有前导下划线的标识符。除了使代码成为阅读之前的痛苦之外,您还可以快速找到自己使用实现保留的标识符。在这里情况并非如此,但我愿意打赌这不是故意的。

  2. 您还需要一个赋值运算符来完成Rule of Three。值得庆幸的是,一个像样的复制构造函数可以实现这一点。

  3. 不要任何。这就是为什么,在设计决策中大肆挥霍和咬牙切齿的时候,多年来的全能C ++标准委员会已选择用std::vector<>祝福我们。如果你这样做是为了学习,那就好。你最终将学到的是,一旦你拥抱标准图书馆及其所有的内疚乐趣,你很少需要。

  4. 如果这是一个学习练习,请赞扬,并幸福地忽略上述(3)。对于(2),您可以使用copy/swap idiom现在您拥有合理的复制文件:

    Array& Array::operator =(Array obj) // value-param intentional
    {
        std::swap(_arr, obj._arr);
        std::swap(_size, obj._size);
        return *this;
    }
    

    祝你好运。

答案 1 :(得分:0)

_size没有初始值,因为您在使用它之前没有将其作为参数传递或在其他地方初始化。

另外,请勿*_arr[i] = *obj._arr[i];

它没有意义,因为arr[i]本身意味着*(arr+i)

执行:

_arr[i] = obj._arr[i];

答案 2 :(得分:0)

当你这样做时,你应该没事

Array::Array( const Array & obj ):
    _size(obj._size) 
{
    _arr = new int[_size];

    for(int i=0;i<_size;i++)
        _arr[i] = obj._arr[i];
}

在第2行,您会获得初始化列表,请阅读此http://www.cprogramming.com/tutorial/initialization-lists-c++.html

关键是,当您编写自定义复制构造函数时,只会复制您明确表示要复制的内容。复制构造函数将首先为所有成员调用默认的initilizer,除非您使用初始值设定值。

另外,对于性能的微小提示,你有没有看过memcpy? http://www.cplusplus.com/reference/cstring/memcpy/它可能更有效:D

我注意到的另一件事是你取消引用* _arr [i],它不是指针而是对值的引用。

编辑有人注意到我的更好甚至不是更好。我改变了它。

答案 3 :(得分:0)

正在复制的原始类型_size实际上是一个真实的陈述,但你没有指定完整的句子。
当您没有声明复制构造函数时,默认实现将是这个

Array::Array( const Array & obj )
{
    this._size = obj._size;
    this._arr = obj._arr;
}

您不希望这样,因为复制的对象将共享_arr变量 但是,当您实现了复制构造函数时,您需要完全实现它。 在您的情况下,您没有使用_size的值。因此它将是未定义的。

编译失败是由行*_arr[i] = *obj._arr[i];引起的。您使用*使用非法间接。只需使用_arr[i] = obj._arr[i];进行复制即可。

答案 4 :(得分:0)

这是我的解决方案。也许会有所帮助。

Array.h

#pragma once
class Array {

public:

    Array();
    Array(int size);
    Array(const Array& src);
    Array operator=(const Array& rhs);
    ~Array();

    void readInValues();
    void mult(int num);
    void add(int num);
    void printArray();

private:
    int *_arr;
    int _size;

};

我在参考三条规则时添加了赋值运算符。它是Array.cpp

#include "Array.h"

Array::Array()
    :_size(10) {

    _arr = new int[_size];
}

Array::Array(int size)
    : _size(size) {

    _arr = new int[_size];
}

Array::Array(const Array& src) {
    _size = src._size;
    _arr = new int[_size];

    for (int i = 0; i < _size; i++) {
        _arr[i] = src._arr[i];
    }
}

Array Array::operator=(const Array& rhs) {
    if (this == &rhs) {
        return (*this);
    }

    delete[] _arr;

    _size = rhs._size;
    _arr = new int[_size];

    for (int i = 0; i < _size; i++) {
        _arr[i] = rhs._arr[i];
    }
}

Array::~Array() {
    delete[] _arr;
}