【问题标题】:Overload operator + for custom vector class重载运算符 + 用于自定义矢量类
【发布时间】:2021-08-06 01:05:42
【问题描述】:

每个人。

我有问题。我想通过重载运算符+对两个向量求和,并将结果分配给第三个向量。但是当我将两个向量的值相加时,我将结果保存在临时向量中,最后我返回该向量。但是当总和完成时,临时向量调用析构函数并释放值。我该如何解决这个问题?

P.S 我对其他运营商有一些问题。但我认为其他人的救赎是一样的。

// Vector class definition
       template <class T> class Vector
       {
           private:
               unsigned x; // used to store size of vector
               T *vector;
           public:
               Vector();
               Vector(unsigned x);
               Vector(std::initializer_list<T> list);
               ~Vector();
               void random(T min, T max);
               void resize(unsigned x);
               unsigned size(void);
               T &front(void);
               T &back(void);
               void operator*=(Vector<T> &vector);
               void operator/=(Vector<T> &vector);
               void operator%=(Vector<T> &vector);
               void operator+=(Vector<T> &vector);
               void operator-=(Vector<T> &vector);
               Vector<T> operator*(Vector<T> &vector);
               Vector<T> operator/(Vector<T> &vector);
               Vector<T> operator%(Vector<T> &vector);
               Vector<T> operator+(Vector<T> &vector);
               Vector<T> operator-(Vector<T> &vector);
               T &operator[](int i);
       };

/* Vector Constructors */
template <class T> Vector<T>::Vector()
{

}

template <class T> Vector<T>::Vector(unsigned x)
{
    Vector::x = x;
    Vector::vector = new T[Vector::x];
}

template <class T> Vector<T>::Vector(std::initializer_list<T> list)
{
    Vector::x = list.size();
    Vector::vector = new T[Vector::x];

    auto it = list.begin();
    for(int i = 0; i < Vector::x; i++, it++)
        Vector::vector[i] = *it;
}

/* Destructor */
template <class T> Vector<T>::~Vector()
{
    delete[] Vector::vector;
}
template <class T> void Vector<T>::random(T min, T max)
{
    assert(std::is_arithmetic<T>::value);
    
    std::random_device rd;
    std::mt19937 eng(rd());

    if constexpr(std::is_floating_point<T>::value)
    {
        std::uniform_real_distribution<T> dist(min, max);

        for(int i = 0; i < Vector::size(); i++)
            Vector::vector[i] = dist(eng);
    }
    else
    {
        std::uniform_int_distribution<T> dist(min, max);

        for(int i = 0; i < Vector::size(); i++)
            Vector::vector[i] = dist(eng);
    }
}


template <class T> Vector<T> Vector<T>::operator+(Vector<T> &vector)
{
    assert(Vector::size() == vector.size());

    Vector<T> output(Vector::size());

    for(int i = 0; i < Vector::size(); i++)
        output[i] = Vector::vector[i] + vector[i];

    return output; // after this line output vector is deallocated :(
}

int main(int argc, char *argv[])
{
    Vector<float> *vector1 = new Vector<float>(3);
    Vector<float> *vector2 = new Vector<float>(3);
    Vector<float> *vector3 = new Vector<float>;

    vector1->random(-1.0f, 1.0f);
    vector2->random(-1.0f, 1.0f);
    *vector3 = *vector1 + *vector2;

    delete vector1;
    delete vector2;
    delete vector3; // here's SIGABORT results, even if vectors are not pointers (they will be deallocated before return anyway)

    return 0;
}

【问题讨论】:

  • 你必须遵循The Rule of Three:定义复制构造函数和赋值运算符来复制数组的内容而不是指针。
  • 这是一个Rule of Three/Five 问题。您已经实现了自定义析构函数,因此您还需要实现自定义复制/移动构造函数和复制/移动赋值运算符。
  • 也许您可以改用std::valarray
  • 也许,您可以将调试输出添加到构造函数和析构函数。您可能会惊讶于他们何时何地被调用...
  • 我已经调试过了。当 operator+ 返回结果时数据被破坏。然后在 main 函数中 vector3 尝试再次释放该数据。我尝试上面提到的三个规则并写出结果。

标签: c++ class templates vector


【解决方案1】:

稍微修改了代码。谢谢大家的回答。

template <class T> class Vector
    {
        private:
            unsigned x; // used to store size of vector
            T *vector;
        public:
            Vector();
            Vector(unsigned x);
            Vector(std::initializer_list<T> list);
            Vector(const Vector<T> &vector);
            ~Vector();
            void random(T min, T max);
            void resize(unsigned x);
            unsigned size(void) const;
            T &front(void) const;
            T &back(void) const;
            Vector<T> operator+(const Vector<T> &vector);
            Vector<T> &operator=(const Vector<T> &vector);
            T &operator[](int i) const;
    };

/* Vector Constructors */
template <class T> Vector<T>::Vector()
{

}

template <class T> Vector<T>::Vector(unsigned x)
{
    Vector::x = x;
    Vector::vector = new T[Vector::x];
}

template <class T> Vector<T>::Vector(std::initializer_list<T> list)
{
    Vector::x = list.size();
    Vector::vector = new T[Vector::x];

    auto it = list.begin();
    for(int i = 0; i < Vector::x; i++, it++)
        Vector::vector[i] = *it;
}

/* Copy constructor */
template <class T> Vector<T>::Vector(const Vector<T> &vector)
{
    Vector::x = vector.x;
    
    Vector::vector = new T[Vector::x];
    
    for(int i = 0; i < Vector::x; i++)
        Vector::vector[i] = vector[i];
}

/* Destructor */
template <class T> Vector<T>::~Vector()
{
    delete[] Vector::vector;
}

template <class T> Vector<T> Vector<T>::operator+(const Vector<T> &vector)
{
    assert(Vector::size() == vector.size());

    Vector<T> output(vector.size());

    for(int i = 0; i < Vector::size(); i++)
        output[i] = Vector::vector[i] + vector[i];

    return output;
}

template <class T> Vector<T> &Vector<T>::operator=(const Vector<T> &vector)
{
    if(this == &vector)
        return *this;

    Vector::x = vector.x;
    
    for(int i = 0; i < Vector::size(); i++)
        Vector::vector[i] = vector[i];

    return *this;
}

template <class T> T & Vector<T>::operator[](int i) const
{
    return Vector::vector[i];
}

int main(int argc, char *argv[])
{
    Vector<int> vector1 = { 1, 2, 3 }, vector2 = vector1, vector3 = vector1 + vector2;
    std::cout << vector1 << std::endl << vector2 << std::endl << vector3 << std::endl;

    return 0;
}

结果:

darvlinig@gentoo ~/tests/test.cpp $ ./test 
[1, 2, 3] 
[1, 2, 3]
[2, 4, 6]
darvlinig@gentoo ~/tests/test.cpp $

【讨论】:

  • 赋值运算符错误。您没有删除旧内存,而是为新内存分配。如果传入的Vector 的元素比this 多怎么办?一个正确的赋值运算符会这样做:Vector&lt;T&gt; temp = vector; std::swap(temp.x, x); std::swap(temp.vector, vector); return *this;
  • 其次,不需要在所有这些代码行中添加Vector::。例如delete[] vector; 而不是delete[] Vector::vector;
  • 除此之外,这里有一个简单的失败的单行程序:int main() {Vector&lt;int&gt; v;}。它失败的原因是你没有在Vector的默认构造函数中初始化成员变量,因此在析构函数中对delete[]的调用使用了一个未初始化的指针值。
  • Valgrind 告诉我们不可能有泄漏并且所有内存都被释放了。无论如何,我在从其他向量分配新值时没有检查向量的大小,这是一个错误。谢谢你的回复,我已经解决了。
猜你喜欢
  • 2013-08-15
  • 1970-01-01
  • 2018-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多