未初始化的复制错误

时间:2014-07-13 06:41:22

标签: c++ c++11 iterator allocator

我正在尝试使用自己的矢量类时遇到错误。更具体地说,它是一个模板化的类,使用std :: allocator类进行内存分配。更具体地说,错误在我的范围构造函数中,它接收2个输入迭代器并使用" uninitialized_copy"用于复制目的的功能。这是代码的存根

#include <memory>
#include <iostream>

template <typename T, typename allocator_type = std::allocator<T>>
class vector
{
public:

// fill ctor 2
vector (size_t n, const T& val,
        const allocator_type& alloc = allocator_type())
  : my_alloc(alloc),
    begin_(my_alloc.allocate(n)),
    end_(begin_ + n),
    size_(n),
    capacity_(n)
{
  std::uninitialized_fill(begin(), end(), val);
}

// range ctor
template <typename InputIterator>
vector (InputIterator first, InputIterator last,
      const allocator_type& alloc = allocator_type())
  : my_alloc(alloc),
    size_(0),
    begin_(0),
    end_(0),
    capacity_(0)
{
  // Poor method for finding input container size, a better solution perhaps?
  InputIterator f = first;
  while (f++ != last)
  ++size_;

  begin_ = my_alloc.allocate(size());
  end_ = begin_ + size();
  capacity_ = size();

  std::uninitialized_copy(first, last, begin_);
}

  T* begin() { return begin_; }
  T* end() { return end_; }
  size_t size() { return size_; }
  size_t capacity() { return capacity_; }

private:
  allocator_type my_alloc;
  size_t size_, capacity_;
  T* begin_, *end_;
};

int main()
{
  vector<int> lst(10, 5);
  vector<int> lst2(lst.begin(), lst.end());
}

现在当我编译时,我收到一个错误,其中有一些关于&#34;在struct std :: iterator_traits中没有类型名为value_type,这很奇怪,因为我的其他类型的构造函数,如填充和复制构造函数是精细。另外,我还注意到编译器推断出&#34; InputTterator&#34;类型为&#34; int&#34;而不是&#34; int *&#34;。

过去几个小时我一直在试着调试它,但似乎无法找到任何解决方案。任何帮助将不胜感激。

谢谢!

编辑:对不起!我的错误。作为模板参数的一部分发送2个整数并不是故意的。我编辑了上面的代码。它现在有一个适当的填充ctor和范围ctor。主要功能现在基于这些ctors创建2个向量。错误仍然存​​在。再一次,我的错误很大!

1 个答案:

答案 0 :(得分:1)

  

我还注意到编译器推断了&#34; InputTterator&#34;类型为&#34; int&#34;而不是&#34; int *&#34;。

当然它确实如此,你向int传递了一个构造函数的参数:

vector<int> lst(10, 5);  // what else can it deduce than int?

您得到的错误是因为iterator_traits<int>内部使用的专业化uninitialized_copy确实没有value_type成员。

你应该做什么(为了避免超出输入范围只是为了获得它的大小)是这样的(partialy伪代码):

  InputIterator f = first;
  size_t current_size = 0;
  while (f != last) {
      if (current_size < size_) {
          new (begin+current_size) T(*f);
          ++current_size;
      } else {
          // allocate new buffer and copy any
          // existing elements over
          // (think about exception safety here)
      }
      ++f;
  }

这是输入迭代器的最佳选择。另一种选择是检查InputIterator的迭代器类别,以便在允许算术运算时,您可以将标签分派到预先计算大小的实现。

编辑(响应OP的编辑):

所以你的问题是带有两个迭代器的构造函数模板在你不想要的地方被调用。在C ++ 11之前,标准库的向量类中存在同样的问题。该标准解释说,当推导出的类型不是迭代器时,构造函数不参与重载解析。您可以使用SFINAE执行相同的操作:

template <typename InputIterator,
    typename ValueType = typename std::iterator_traits<InputIterator>::value_type>
vector (InputIterator first, InputIterator last,
      const allocator_type& alloc = allocator_type());

现在,当std::iterator_traits<InputIterator>::value_type不存在时,重载解析将在模板参数替换期间丢弃重载,而另一个将被替换。