我的 Copy and Move 构造函数和赋值运算符出现问题

Problem with my Copy and Move constructor and assignment operators

提问人:DvB 提问时间:2/10/2022 最后编辑:Remy LebeauDvB 更新时间:2/10/2022 访问量:151

问:

我想用 C++ 构建自己的完整类。我是这样开始的:Vector

#include <iostream>
#include <initializer_list>

#define Print(x)(std::cout<< x << std::endl)

// Vector Class // 
template <typename T>
class Vector
{
    // Attributes
    int length = 0;
    T* array;

    public:
   
    // Default constructor
    Vector()
    : length(0), array(nullptr)
    { }

    // Copy constructor 
    template<typename U>
    Vector(const Vector<U>& other)
        : Vector(other.len())
    {
        Print("Use Copy Constructor");
        // Coppying other data to new array
        array = new T[other.len()];
        for (auto i=0; i < other.len(); i++)
            array[i] = other[i];
    }

    // Move constructor
    Vector(Vector<T>&& other)
        : length(other.len()), array(other.array)
    {
        Print("Use Move Constructor");
        // Deleting other array
        other.length = 0;
        other.array = nullptr;
    }

    // Constructor (does not allow uniform initialisation)
    Vector(int length)
    : length(length), array(new T[length])
    { }

    // Constructor (with initialiser list and delegate constructor)
    Vector(std::initializer_list<T> list)
    : Vector((int)list.size())
    {
        std::uninitialized_copy(list.begin(), list.end(), array);
    }

    // Destructor
    ~Vector()
    {
        length = 0;
        delete[] array;
        array = nullptr;
    }

    // Function Len that returns the length 
    int len() const
    {
        return length;
    }
    // Operator[](int i) and its const overload
    auto& operator[](int i)
    {
        return array[i];
    }
    
    auto& operator[](int i) const
    {
        return array[i];
    }

    // Copy assignment operator 
    template<typename U>
    Vector& operator=(const Vector<U>& other)
    {
        Print("Use Copy Operator");
        if (this != (Vector*)& other) {
            /*
            This works the same way but does not solve the problem: 
    
            Vector<typename std::common_type<T,U>::type> temp(other);
            temp.swap(*this); 
            */ 

            delete[] array;
            length = other.len();
            array = new T[other.len()];
            for (auto i = 0; i < other.len(); i++)
                array[i] = other[i];
        }
        return *this;
    }

    // Move assignment opertator
    Vector& operator=(Vector<T>&& other)
    {
        Print("Use Move Operator");
        if (this != (Vector*)&other){
            /*
            This works the same way but does not solve the problem: 

            Vector<T> temp(std::move(other)); // moves the array
            temp.swap(*this);
            */ 

            delete[] array;
            length = other.len();
            array   = other.array;
            other.len() = 0;
            other.array   = nullptr;
        }
        return *this;
    }
};

但是,如果我现在尝试像这样使用复制分配运算符:

Vector<double> double_vector = {3.4677, 3.212, 2.2, 6.3};
Vector<double> a = double_vector;

我收到以下错误消息:

错误:使用已删除的函数“constexpr Vector<double>::Vector(const Vector<double>&)”

我认为问题出在复制构造函数和复制赋值运算符上,但遗憾的是我找不到解决方案。我觉得奇怪的是,如果我注释掉移动构造函数和移动赋值运算符,代码似乎确实有效。这让我认为编译器很难知道要使用哪个构造函数。但我也可能对此大错特错。

希望我提供了足够的信息来回答/推动正确的方向。

C++ 构造函数 复制 移动 值运算符

评论

1赞 user4581301 2/10/2022
警告:向其分配存储的委托。该存储在 的复制构造函数中泄露。: Vector(other.len())Vector(int length)array = new T[other.len()];
0赞 user4581301 2/10/2022
解决方案:删除模板中的模板。它们在这里没有多大意义。 -> .专用的 on 可能与专用的 on 不同,因此复制构造函数不再是复制构造函数。更多详细信息,请参阅为什么标准不将模板构造函数视为复制构造函数?template<typename U> Vector(const Vector<U> &other)Vector(const Vector &other)VectorUVectorT
0赞 user4581301 2/10/2022
我建议对模板中的所有其他模板方法执行相同的操作Vector
0赞 user4581301 2/10/2022
无论如何,您为什么决定将复制构造函数和赋值运算符模板化?那里有一个有趣的故事,一个需要吸取的教训,或者两者兼而有之。
0赞 DvB 2/10/2022
谢谢你的回答。尝试计算 Vector<double> double_vector = {3.4677, 3.212, 2.2, 6.3};向量<双倍> a = double_vector;删除模板确实就足够了。但是,我也希望能够计算:Vector<double> double_vector = {3.4677, 3.212, 2.2, 6.3};向量<int> b = double_vector;b.display();和: vector<int> integer_vector = {3, 2, 4, 7};向量<双精度>d = integer_vector;d.display();但是,当删除模板时,这不起作用。

答:

2赞 BoP 2/10/2022 #1

模板从来都不是复制构造函数,而是转换构造函数。

由于您已经定义了一堆其他构造函数,否则默认的复制构造函数将被定义为已删除。

评论

0赞 user4581301 2/10/2022
据我所知,正确的诊断,但我建议添加一个解决方案。
0赞 BoP 2/10/2022
@user4581301 - 我认为第一句话让 OP 添加一个不是模板的复制构造函数变得“明显”。
0赞 user4581301 2/10/2022
我,我会删除模板,但我明白你的意思。使用一些 SFINAE 来确保所包含的类型是可转换的,转换构造函数可能很有用。