1

I want to build my own full Vector class in C++. I started like this:

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

But if I now try to use the copy assignment operator like this:

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

I get the following error message:

error: use of deleted function 'constexpr Vector<double>::Vector(const Vector<double>&)'

I assume that the problem lies within the copy constructor and copy assignment operator, but I sadly can't find a solution. What I find strange is that, if I comment out the move constructor and move assignment operator, the code does seem to work. This lets me think that the compiler has difficulty knowing which constructor to use. But I could also be very wrong about this.

Hope I gave enough info for an answer/push in the right direction.

6
  • 1
    Warning: The : Vector(other.len())delegates to Vector(int length) which allocates storage. That storage is leaked in the copy constructor at array = new T[other.len()];. Commented Feb 9, 2022 at 23:19
  • Solution: Remove the templates in the template. they don't make much sense here. template<typename U> Vector(const Vector<U> &other) -> Vector(const Vector &other). A Vector specialized on U may not be the same as a Vector specialized on T, so the copy constructor stops being a copy constructor. More details at Why doesn't the standard consider a template constructor as a copy constructor? Commented Feb 9, 2022 at 23:30
  • I recommend doing the same to all of the other template methods inside the Vector template Commented Feb 9, 2022 at 23:31
  • Why did you decide to template the copy constructor and assignment operator, anyway? There's an interesting story, a lesson to be learned, or maybe both, there. Commented Feb 9, 2022 at 23:38
  • Thanks for the answer. When trying to compute Vector<double> double_vector = {3.4677, 3.212, 2.2, 6.3}; Vector<double> a = double_vector; It is indeed sufficient to remove the template. However, I also want to be able to compute: Vector<double> double_vector = {3.4677, 3.212, 2.2, 6.3}; Vector<int> b = double_vector; b.display(); And: Vector<int> integer_vector = {3, 2, 4, 7}; Vector<double> d = integer_vector; d.display(); This does however not work when the template is removed. Commented Feb 10, 2022 at 12:44

1 Answer 1

2

A template is never a copy constructor, that is a converting constructor.

And as you have defined a bunch of other constructors, the otherwise default copy constructor will be defined as deleted.

Sign up to request clarification or add additional context in comments.

3 Comments

Near as I can tell, the right diagnosis, but I recommend adding a solution.
@user4581301 - I thought the first sentence made it "obvious" for the OP to add a copy constructor that is not a template.
Me, I'd remove the templating, but I see your point. With a bit of SFINAE to ensure the contained types are convertible the converting constructor might be useful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.