C++ 假设我有赋值运算符,我的复制构造函数是this=obj可以吗?

C++ 假设我有赋值运算符,我的复制构造函数是this=obj可以吗?,c++,copy-constructor,assignment-operator,C++,Copy Constructor,Assignment Operator,本质上,我的问题如下:假设我为一个类创建了一个赋值操作符,让我的复制构造函数仅仅是this=item是违反惯例还是不赞成 假设我正在创建一个仅包含以下数据的模板类: private: int _size; ItemType* _array; 如果我的赋值运算符如下所示: template<class ItemType> void obj<ItemType>::operator = (const obj & copyThis){

本质上,我的问题如下:假设我为一个类创建了一个赋值操作符,让我的复制构造函数仅仅是this=item是违反惯例还是不赞成

假设我正在创建一个仅包含以下数据的模板类:

private:
    int       _size;
    ItemType* _array;
如果我的赋值运算符如下所示:

template<class ItemType>
void obj<ItemType>::operator = (const obj & copyThis){
    _size = copyThis.getSize(); 
    _array = new ItemType[_size];
    for (int i = 0; i < _size; i++){
        //assuming getItemAt is a function that returns whatever is in given location of object's _array
        _array[i] = copyThis.getItemAt(i);
    }
}
模板
void obj::operator=(const obj和copyThis){
_size=copyThis.getSize();
_数组=新的ItemType[_size];
对于(int i=0;i<\u size;i++){
//假设getItemAt是一个函数,它返回对象的_数组的给定位置中的任何内容
_数组[i]=copyThis.getItemAt(i);
}
}
那么,如果我的复制构造函数简单地如下所示,是否会违反惯例/被轻视/被认为是不正确的

template<class ItemType>
obj<ItemType>::obj(const obj & copyThis){
    this = copyThis;
}
模板
obj::obj(const obj和copyThis){
这个=复制这个;
}

在复制构造函数中调用
运算符=
通常是安全的(只要
运算符=
不尝试将复制构造函数用作其逻辑的一部分)

但是,您的
操作符=
一开始就实现错误。它泄漏内存,不处理分配给自身的
,也不返回对
的引用

请尝试以下方法:

template<class ItemType>
obj<ItemType>::obj(const obj & copyThis)
    : _size(0), _array(0)
{
    *this = copyThis;
}

template<class ItemType>
obj<ItemType>& obj<ItemType>::operator=(const obj<ItemType> &copyThis)
{
    if (this != &copyThis)
    {
        int newSize = copyThis.getSize(); 
        ItemType *newArray = new ItemType[newSize];

        // consider using std::copy() instead:
        //
        // std::copy(copyThis._array, copyThis._array + newSize, newArray);
        //
        for (int i = 0; i < newSize; ++i) {
            newArray[i] = copyThis.getItemAt(i);
        }

        delete[] _array;
        _array = newArray;
        _size = newSize; 
    }

    return *this;
}
如果添加
swap
方法,可以稍微清理一下:

template<class ItemType>
obj<ItemType>::obj(const obj & copyThis)
    : _size(copyThis.getSize()), _array(new ItemType[_size])
{
    for (int i = 0; i < _size; ++i){
        _array[i] = copyThis.getItemAt(i);
    }
}

template<class ItemType>
void obj<ItemType>::swap(obj<ItemType> &swapThis)
{
    std::swap(_array, swapThis._array);
    std::swap(_size, swapThis._size);
}

template<class ItemType>
obj<ItemType>& obj<ItemType>::operator=(const obj<ItemType> &copyThis)
{
    if (this != &copyThis) {
        obj<ItemType>(copyThis).swap(*this); 
    }

    return *this;
}
模板
obj::obj(const obj和copyThis)
:_size(copyThis.getSize()),_数组(新项目类型[_size])
{
用于(int i=0;i<_size;++i){
_数组[i]=copyThis.getItemAt(i);
}
}
样板
void obj::swap(obj&swapThis)
{
std::swap(_数组,swapThis._数组);
标准:交换(交换大小,交换大小);
}
样板
obj&obj::operator=(const obj©This)
{
如果(此!=&复制此){
obj(copyThis).swap(*this);
}
归还*这个;
}

也就是说,如果用
std::vector
替换手动数组,则根本不需要手动实现复制构造函数或复制赋值运算符,编译器生成的默认数组就足够了(因为
std::vector
已经实现了复制语义).

您是否尝试编译它?您的赋值运算符将泄漏内存,并且不会处理自赋值。您的复制构造函数已损坏。它正在泄漏内存。因此,您将得到一个基本正常的构造函数,以及一个损坏的副本构造函数,它会像筛子一样泄漏内存。
operator=
将数据从一个现有对象复制到另一个现有对象,因此在替换它之前,您必须
删除[]
现有的旧数组。您没有这样做,因此您正在泄漏旧数组。@ethanbin您对
的理解不正确。参见C++标准的第93.2节,“<代码>类型> <代码>在<代码>类< <代码> x的成员函数中是“代码> x*< /代码>”“啊,这说明了我犯的错误,其他人都在评论得非常清楚,谢谢!但是,除了在副本构造函数中调用
操作符=
是安全的之外,这是违反惯例的还是被视为不寻常的?如果我错了,请纠正我,但是实现
操作符=
作为按值取参数不是很常见,所以您可以使用make
操作符=
nothrow
,一般来说,重复数据消除/简化您的代码?@ShadowRanger:这是一种常见的实现方式,尽管它确实会产生副作用,即使是为了自我分配,也会始终制作副本。正如您在我的回答中所看到的,即使参数是通过常量引用传递的,复制和交换仍然是一个选项,但至少自赋值可以避免复制。@RemyLebeau:True。我通常认为它可以避免向公共(非自赋值情况)增加开销,特别是对于有效地使用rVals(因为它完全可以避免复制操作)。@ StutoRangeRe:当使用C++ 11和以后的R值引用时,通常通过值传递参数更有意义,并让编译器决定是使用复制还是移动语义(前提是两者都正确实现)。对于较早的C++版本,通过const引用反而更有意义。
template<class ItemType>
obj<ItemType>::obj(const obj & copyThis)
    : _size(copyThis.getSize()), _array(new ItemType[_size])
{
    for (int i = 0; i < _size; ++i){
        _array[i] = copyThis.getItemAt(i);
    }
}

template<class ItemType>
void obj<ItemType>::swap(obj<ItemType> &swapThis)
{
    std::swap(_array, swapThis._array);
    std::swap(_size, swapThis._size);
}

template<class ItemType>
obj<ItemType>& obj<ItemType>::operator=(const obj<ItemType> &copyThis)
{
    if (this != &copyThis) {
        obj<ItemType>(copyThis).swap(*this); 
    }

    return *this;
}