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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24227980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:40:38  来源:igfitidea点击:

C++ copy constructor for class with dynamically allocated array

c++arrayscopy-constructordynamic-allocation

提问by user34920

Just starting on C++ (a few days now), I come with C background.

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

I have a class that holds, mainly, an a pointer to an int array with the following code:

我有一个类,主要包含一个指向 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 is a pointer to an int array, when creating a new instance using the copy constructor I would to create a new int array on the heap (I think). In the copy constructor:

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

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

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

The 1st thing I do is allocate memory for the new array (_size is a primitive type so being copied automatically as far as I understood). The next thing I would like to do is copy the array itself using a loop. This parts fails the compilation saying illegal indirection. I am not sure why...

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

回答by WhozCraig

This:

这个:

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

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

could be this:

可能是这样的:

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);
}

Specifically, note the use of the initializer list. Other things worth mentioning:

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

  1. Don't use identifiers with leading underscores. Besides making the code a royal pain to read, you can quickly find yourself using identifiers that are reserved by the implementation. That isn't the case here, but I'm willing to bet that wasn't by intent.

  2. You also need an assignment operator to fulfill the Rule of Three. Thankfully, a decent copy constructor makes that trivial.

  3. Don't do anyof this. This is why, with great wailing and much gnashing of teeth in design decisions, the almighty C++ standards committees of years-gone-by have so-chosen to bless us with std::vector<>. If you're doing this to learn, good. What you'll eventually learn is how rarely you needto once you embrace the standard library and all its guilty pleasures.

  1. 不要使用带前导下划线的标识符。除了让代码读起来非常痛苦之外,您还可以很快发现自己使用了由实现保留的标识符。情况并非如此,但我敢打赌这不是故意的。

  2. 您还需要一个赋值运算符来满足三规则。值得庆幸的是,一个体面的复制构造函数使这变得微不足道。

  3. 不要做任何这些。这就是为什么,在设计决策中,全能的 C++ 标准委员会在设计决策中发出了巨大的哀号和咬牙切齿的声音,却选择用std::vector<>. 如果你这样做是为了学习,很好。你最终会学到的是,一旦你接受了标准库及其所有的罪恶乐趣,你很少要这样做了。

If this is intended as a learning exercise, kudos, and blissfully ignore (3) above. For (2), you can use the copy/swap idiomnow that you have a reasonable copy-ctor:

如果这旨在作为学习练习,请点赞,并完全忽略上面的 (3)。对于 (2),您现在可以使用复制/交换习语,因为您有一个合理的复制构造函数:

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

Best of luck.

祝你好运。

回答by user34920

_sizehas no initial values, since you have not passed it either as arguements or initialized anywhere else before using it.

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

Also, don't do *_arr[i] = *obj._arr[i];

还有,不要做 *_arr[i] = *obj._arr[i];

It doesn't make sense as arr[i]itself means *(arr+i).

arr[i]本身的意思是没有意义的*(arr+i)

Do:

做:

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

回答by Pinna_be

when you do this, you should be fine

当你这样做时,你应该没问题

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

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

on line 2 you get the intializer list, read this http://www.cprogramming.com/tutorial/initialization-lists-c++.html

在第 2 行你得到了初始化列表,阅读这个http://www.cprogramming.com/tutorial/initialization-lists-c++.html

The point is, when you write a custom copy constructor, only the things you explicitly say you copy will be copied. The copy constructor will first call the default initilizer for all members except when you use the initializer value.

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

Also, a tiny hint for performance maybe, did you look into memcpy? http://www.cplusplus.com/reference/cstring/memcpy/it might be more efficient :D

另外,也许是一个关于性能的小提示,你有没有研究过 memcpy?http://www.cplusplus.com/reference/cstring/memcpy/它可能更有效:D

another thing I noticed is that you dereference *_arr[i], which is not a pointer but a reference to the value.

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

EDIT someone noticed that my even better was actually not better. I changed it.

编辑有人注意到我的更好实际上并没有更好。我改变了它。

回答by Pratham

_size being a primitive type is being copied is actually a true statement, but you didn't specify the complete sentence.
When you don't declare a copy constructor the default implementation will be something as this

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

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

Which is what you don't want as the copied object will share the _arr variable.
But as you have implemented the copy constructor you need to implement it fully. In your case you not not used the value of _size. Hence it would be undefined.

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

The compilation failure is due to the line *_arr[i] = *obj._arr[i];. You are using an illegal indirection using the *. Just use _arr[i] = obj._arr[i];to copy it.

编译失败是由于行*_arr[i] = *obj._arr[i];。您正在使用 *. 只是_arr[i] = obj._arr[i];用来复制它。

回答by M.Bary?owicz

It's my solution. Maybe will help.

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

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;

};

I added the assignment operator in reference to the three rule. And it's Array.cpp

我参考三个规则添加了赋值运算符。它是 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;
}