在自定义 class 中调用 a=s+b 导致 s(或 b)也受到影响(甚至当声明为常量时)

In custom class when calling a=s+b causing s (or b) also be effected (and even when declared as constant)

所以最近我正在使用我的自定义 class,当我执行算术运算时,它也会影响方程中的参数(因此当调用 auto a=s+b 时也会导致 s 正在改变)。即使我将这些变量声明为 const 并将参数全部传递给值(不是引用)。

所以这是我的 classes 代码的(部分):

template<typename T>
struct coord {
    T *d;
    long unsigned int dim;
    coord(di dim, T val=0.0): dim(dim) {
        d=new T[dim];
        for(di i=0;i<dim;i++) {
            d[i]=val;
        }
    }
    coord(initializer_list<T> l): dim{l.size()} {
        //d=(T *)calloc(dim, sizeof(T));
        d=new T[dim];
        copy(l.begin(), l.end(), d);
    }
    coord<T> operator+=(const coord<T> &r) {
        //for(int i=0; i<(r.dim<this->dim?r.dim:this->dim); i++) {
        if(r.dim>this->dim) {
            throw "Addition's rhs has larger Dimension than lhs.";
        }
        for(di i=0; i<r.dim; i++) { this->d[i]+=r[i]; }
        return *this;
    }
    T& operator[](int i) {
        return d[i];
    }
    T operator[](int i) const {
        return d[i];
    }
    friend coord<T> operator+(coord<T> lhs, const coord<T> &r) { return lhs+=r; }
};

当我执行以下主要代码时:

int main() {
    coord<double> s({3,2,3});
    coord<double> b({3,2,3});
    cout << s << endl;
    auto a=s+b;
    s+=b;
    cout << s << endl << b << endl << a << endl;
    return 0;
}

它给出了输出:

3, 2, 3
3, 2, 3
9, 6, 9
9, 6, 9

其中第一个是原来的s,其他的分别是sba后的

然后我想也许我传递了一些东西作为参考,所以我回到代码并将所有内容更改为按值传递(现在只更改 + 操作)到以下代码:

coord<T> operator+=(coord<T> r) {
    //for(int i=0; i<(r.dim<this->dim?r.dim:this->dim); i++) {
    if(r.dim>this->dim) {
        throw "Addition's rhs has larger Dimension than lhs.";
    }
    for(di i=0; i<r.dim; i++) { r[i]+=this->d[i]; }
    return r;
}
friend coord<T> operator+(coord<T> lhs, const coord<T> r) { return lhs+=r; }

这次给了:

3, 2, 3
9, 6, 9
3, 2, 3
9, 6, 9

基本上我们可以假设加法运算会影响原始变量。但这不应该发生,因为我们按值而不是引用传递参数,那为什么呢?我该如何解决?

没有复制构造函数 and/or 复制赋值,所以当您复制 coord<T> 时,只会复制指针 d,而不是 d 指向的内存到。这可以通过 constructor/assignment 或使用 std::vector 来解决,并让向量为您处理所有内存管理,正如有人指出的那样。使用 std::vector 附带了一堆您不需要的其他东西(例如坐标的尺寸永远不会改变)。像下面这样一个简单的构造函数和复制赋值就可以了。

coord(const coord<T> &other) : dim(other.dim) {
    d = (T *)malloc(dim * sizeof(T));
    memcpy(d, other.d, dim * sizeof(T));
}

coord<T> &operator=(const coord<T> &other) {
    free(d);
    dim = other.dim;
    d = (T *)malloc(dim * sizeof(T));
    memcpy(d, other.d, dim * sizeof(T));
}