【问题标题】:Custom vector class template failing initializer自定义向量类模板失败的初始化程序
【发布时间】:2015-12-03 14:49:57
【问题描述】:

我正在为班级做一个项目,我想我在读完这本书后让自己陷入了困惑。

我们正在构建一个带有模板的自定义矢量类,它将通过一系列测试。

使用我当前的代码,初始化以下语句时失败。

Vector<int> v {1,2,3};

这是我的文件。

矢量.hpp

#ifndef VECTOR_HPP
#define VECTOR_HPP

#include <memory>

template<typename T, typename A = std::allocator<T> >
struct Vector_base {
    A alloc;
    T* elem;
    T* space;
    T* last;

    Vector_base(const A& a, typename A::size_type n) : alloc{a}, elem{alloc.allocate(n)}, space{elem+n}, last{elem+n} { }
    ~Vector_base() { alloc.deallocate(elem,last-elem); }
    Vector_base(const Vector_base&) = delete;

    Vector_base& operator=(const Vector_base&) = delete;
    Vector_base(Vector_base&&);
    Vector_base& operator=(Vector_base&&);
};

template<typename T, typename A = std::allocator<T> >
class Vector {
    Vector_base<T,A> vb;
    void destroy_elements();
public:
    using size_type = typename A::size_type;

    bool is_empty() const
    {
        return this->empty();
    }

    explicit Vector(size_type n, const T& val = T(), const A& = A());

    Vector() {}

    Vector(const Vector& a);
    Vector& operator=(const Vector& a);

    Vector(Vector&& a);
    Vector& operator=(Vector&& a);

    ~Vector() { destroy_elements(); }

    size_type size() const { return vb.space-vb.elem; }
    size_type capacity() const { return vb.last-vb.elem; }

    void reserve(size_type);

    void resize(size_type, const T& = {});
    void clear() { resize(0); }
    void push_back(const T&); 
};

#endif

矢量.cpp

#include "vector.hpp"
#include <memory>

//template<typename T, typename A>
Vector_base<T,A>::Vector_base(Vector_base&& a) : alloc{a.alloc}, elem{a.elem}, space{a.space}, last{a.space}
{
    a.elem = a.space = a.last = nullptr;
}

//template<typename T, typename A>
Vector_base<T,A>& Vector_base<T,A>::operator=(Vector_base&& a)
{
    swap(*this,a);
    return *this;
}

//template<typename T, typename A>
void Vector<T,A>::destroy_elements()
{
    for (T* p = vb.elem; p!=vb.space; ++p)
        p-> ~T();

    vb.space=vb.elem;
}

//template<typename For, typename T>
void uninitialized_fill(For beg, For end, const T& x)
{
    For p;
    try {
        for (p=beg; p!=end; ++p)
            ::new(static_cast<void*>(&*p)) T(x);
    }
    catch (...) {
        for (For q = beg; q!=p; ++q)
            (&*q)-> ~T();
        throw;
    }
}

//template<typename T, typename A>
Vector<T,A>::Vector(size_type n, const T& val, const A& a) : vb{a,n}
{
    uninitialized_fill(vb.elem,vb.elem+n,val);
}


//template<typename T, typename A>
Vector<T,A>::Vector(const Vector<T,A>& a) : vb{a.alloc,a.size()}
{
    std::uninitialized_copy(a.begin(),a.end(),vb.elem);
}

//template<typename T, typename A>
Vector<T,A>::Vector(Vector<T,A>&& a) : vb{move(a.vb)} { }

/*template<typename T, typename A>
Vector<T,A>::Vector(const Vector& a)
{

}*/

//template<typename T, typename A>
Vector<T,A>& Vector<T,A>::operator=(Vector<T,A>&& a)
{
    clear();
    swap(vb,a.vb);
    return *this;
}

//template<typename T, typename A>
Vector<T,A>& Vector<T,A>::operator=(const Vector& a)
{
    if(capacity() < a.size())
    {
        Vector temp {a};
        swap(*this,temp);
        return *this;
    }

    if (this == &a) { return *this; }

    size_type sz = size();
    size_type asz = a.size();
    vb.alloc = a.vb.alloc;
    if (asz<=sz) 
    {
        copy(a.begin(),a.begin()+sz,vb.elem);
        for(T* p = vb.elem+asz; p!=vb.space; ++p)
            p-> ~T();
    }
    else
    {
        copy(a.begin(),a.begin()+sz,vb.elem);
        uninitialized_copy(a.begin()+sz,a.end(),vb.space);
    }
    vb.space = vb.elem+asz;
    return *this;
}

//template<typename T, typename A>
void safe_assign(Vector<T,A>& a, Vector<T,A> b)
{
    swap(a,b);
}

//template<typename T, typename A>
void Vector<T,A>::reserve(size_type newalloc)
{
    if (newalloc<=capacity()) return;
    Vector_base<T,A> b {vb.alloc,newalloc-size()};
    uninitialized_move(vb.elem,vb.elem+size(),b.elem);
    swap(vb,b);
}

//template<typename In, typename Out>
Out uninitialized_move(In b, In e, Out oo)
{
    using T = typename std::iterator_traits<Out>::value_type;
    for (; b!=e; ++b,++oo) {
        new(static_cast<void*>(&*oo)) T{move(*b)};
        b-> ~T();
    }
    return oo;
}

//template<typename T, typename A>
void Vector<T,A>::resize(size_type newsize, const T& val)
{
    reserve(newsize);
    if (size()<newsize)
        uninitialized_fill(vb.elem+size(),vb.elem+newsize,val);
    else
        destroy(vb.elem+newsize,vb.elem+size());
    vb.space = vb.elem+newsize;
}

//template<typename In>
void destroy(In b, In e)
{
    using T = typename std::iterator_traits<In>::value_type;
    for (; b!=e; ++b)
        b-> ~T();
}

//template<typename T, typename A>
void Vector<T,A>::push_back(const T& val)
{
    if (capacity()==size())
        reserve(size()?2*size():8);
    vb.alloc.construct(&vb.elem[size()],val);
    ++vb.space;
}

我在这里错过了什么?

【问题讨论】:

  • 你需要一个构造函数来获取std::initializer_list。另见stackoverflow.com/q/495021/1782465
  • @Clix 为什么你注释掉了template 行?你期待{1,2,3} 调用Vector(size_type n, const T&amp; val, const A&amp;) 过载吗?
  • @LogicStuff 我忘了我还有他们的评论。另一个板上的某个人建议在除头文件之外的任何内容中都不允许使用模板。
  • 是的,没错。但解决方案是将整个定义(带有template 前缀)移动到头文件中。没有其他办法。
  • 我确实最终移动了它们。我仍然收到与以前相同的错误。我相信问题出在 Angew 的建议上。不过,我不太确定如何实现它。

标签: c++ class templates vector


【解决方案1】:

据我所知,所有模板代码都必须在标头中,因为实际的实现是由编译器完成的。初始化失败的原因是编译器找不到你的函数的定义。

将所有代码移至vector.hpp

编辑:另外,您需要一个以initializer_list 作为参数的构造函数。

【讨论】:

  • 这可能不值得回答,但我还不能发表评论。
猜你喜欢
  • 2012-05-21
  • 2018-01-24
  • 1970-01-01
  • 2015-02-08
  • 2013-03-03
  • 2011-10-19
  • 2019-07-02
  • 2017-11-16
  • 2020-03-29
相关资源
最近更新 更多