是矢量的这种行为::调整大小(SIZE_TYPE N)下的C ++ 11和Boost.Container是否正确? [英] Is this behavior of vector::resize(size_type n) under C++11 and Boost.Container correct?

查看:177
本文介绍了是矢量的这种行为::调整大小(SIZE_TYPE N)下的C ++ 11和Boost.Container是否正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有其中的std ::矢量&lt一个C ++应用程序03; T> 类型在整个暂存器使用。因此,他们常常会采用调整的std ::矢量< T> ::调整(),以确保它们足够大,使用前持有所需的数据。在C ++ 03原型这个功能实际上是:

 无效调整大小(SIZE_TYPE N,VALUE_TYPE VAL = VALUE_TYPE());

所以,实际上调用时调整(),矢量是通过添加 VAL 。然而,通常我只需要知道矢量是大到足以容纳我需要的数据;我不需要它与任何值进行初始化。复制 - 构建新的价值只是浪费时间。

C ++ 11来救援(我认为):在它的规范,它拆分调整()成两个重载:

 无效调整大小(SIZE_TYPE N); //初始化值
无效调整大小(SIZE_TYPE N,常量VALUE_TYPE和放大器; VAL); //通过拷贝初始化

这与C ++的理念非常适合:只需支付您所想要的东西。正如我指出的,虽然我的应用程序不能使用C ++ 11的,所以我很高兴,当我遇到了Boost.Container库,其中indicates其文档中此功能支持。具体来说,的boost ::容器::矢量< T> 居然有)的三个重载调整(

 无效调整大小(SIZE_TYPE N); //初始化值
无效调整大小(SIZE_TYPE N,default_init_t); //缺省初始化
无效调整大小(SIZE_TYPE N,常量VALUE_TYPE和放大器; VAL); //通过拷贝初始化

为了验证我明白了一切,我刮起了快速测试,以验证C ++ 11 的std ::矢量&lt行为; T> 的boost ::容器::矢量< T>

 的#include<升压/集装箱/ vector.hpp>
#包括LT&;&iostream的GT;
#包括LT&;矢量>使用命名空间std;
命名空间BC =提振::容器;模板< typename的VecType>
无效init_vec(VecType&安培; 5)
{
    //填充V配合值[0,1,2,3,4,5,6,7,8,9]
    为(为size_t I = 0; I&小于10 ++ⅰ)v.push_back(ⅰ);
    //砍掉的v的结束,这现在应该[1,2,3,4,5],但其他的5个值
    //应保持在内存中
    v.resize(5);
}模板< typename的VecType>
无效print_vec(为const char *标签,VecType&安培; 5)
{
    COUT<<标签<< :;
    用于(为size_t我= 0; I< v.size(); ++ I)
    {
        COUT<< v [1] - ;&下; '';
    }
    COUT<< ENDL;
}诠释的main()
{
    //实例化我们要测试每个类型的载体
    的std ::矢量<&INT GT; std_vec;
    BC ::矢量<&INT GT; boost_vec;
    BC ::矢量<&INT GT; boost_vec_default;    //填入每个矢量以相同的方式
    init_vec(std_vec);
    init_vec(boost_vec);
    init_vec(boost_vec_default);    //现在调整每个向量10个元素在*应*避免重新初始化新元素的方法
    std_vec.resize(10);
    boost_vec.resize(10);
    boost_vec_default.resize(10,BC :: default_init);    //打印每一个出
    print_vec(性病,std_vec);
    print_vec(提升,boost_vec);
    print_vec(助推W /默认,boost_vec_default);
}

在C ++ 03模式 G ++ 4.8.1编译这个如下:

  G ++ vectest.cc
./a.out

产生以下的输出:

  STD:0 1 2 3 4 0 0 0 0 0
提升:0 1 2 3 4 0 0 0 0 0
提升W /默认:0 1 2 3 4 5 6 7 8 9

这是不是太奇怪了。我希望C ++ 03 的std ::矢量< T> 来初始化最后的5种元素零。我甚至可以说服自己,为什么的boost ::容器::矢量< T> 在做同样的(我会假设它在C + + 03模式模拟C ++ 03的行为)。我只得到了,我想,当我专门请教了默认初始化的效果。然而,当我重修于C ++ 11模式如下:

  G ++ vectest.cc -std = C ++ 11
./a.out

我得到这些结果:

  STD:0 1 2 3 4 0 0 0 0 0
提升:0 1 2 3 4 0 0 0 0 0
提升W /默认:0 1 2 3 4 5 6 7 8 9

一模一样!这导致了我的问题:

我错在想,我应该看到每个在这种情况下,三项测试的结果相同?这似乎表明,的std ::矢量< T> 接口的改变并没有真正有过任何影响,因为5个元素在最后调用添加到调整()仍然可以用零初始化前两个案件。


解决方案

不是一个答案,但一个漫长的增编霍华德:我用一个分配器适配器,基本的工作方式相同霍华德的分配器,但更安全,因为


  1. 它只器插入值初始化,而不是的所有的初始化,

  2. 它正确默认初始化。

  //分配器适配器器插入构造()调用
//值转换成初始化默认初始化。
模板< typename的T,类型名A =的std ::分配器< T>>
类default_init_allocator:公​​开发行A {
  的typedef的std :: allocator_traits< A>在;
上市:
  模板< typename的U>结构重新绑定{
    使用其他=
      default_init_allocator<
        U,类型名A_T ::模板rebind_alloc< U>
      取代;
  };  使用A :: A;  模板< typename的U>
  无效结构(U * PTR)
    noexcept(性病:: is_nothrow_default_constructible< U> ::值){
    ::新(的static_cast<无效*>(PTR))U;
  }
  模板< typename的U,类型名称参数... args>
  无效结构(U * PTR,参数数量和放大器;&放大器;参数... args){
    A_T ::构造(的static_cast< A&安培;>(*此),
                   PTR,性病::向前<&参数数量GT;(参数)...);
  }
};

I have a C++03 application where std::vector<T> types are used throughout as temporary buffers. As such, they often get resized using std::vector<T>::resize() to ensure they are large enough to hold the required data before use. The C++03 prototype for this function is actually:

void resize(size_type n, value_type val = value_type());

So in actuality when calling resize(), the vector is enlarged by adding the appropriate number of copies of val. Often, however, I just need to know that the vector is large enough to hold the data I need; I don't need it initialized with any value. Copy-constructing the new values is just a waste of time.

C++11 comes to the rescue (I thought): in its specification, it splits resize() into two overloads:

void resize(size_type n); // value initialization
void resize(size_type n, const value_type &val); // initialization via copy

This fits nicely with the philosophy of C++: only pay for what you want. As I noted, though, my application can't use C++11, so I was happy when I came across the Boost.Container library, which indicates support for this functionality in its documentation. Specifically, boost::container::vector<T> actually has three overloads of resize():

void resize(size_type n); // value initialization
void resize(size_type n, default_init_t); // default initialization
void resize(size_type n, const value_type &val); // initialization via copy

In order to verify that I understood everything, I whipped up a quick test to verify the behavior of C++11 std::vector<T> and boost::container::vector<T>:

#include <boost/container/vector.hpp>
#include <iostream>
#include <vector>

using namespace std;
namespace bc = boost::container;

template <typename VecType>
void init_vec(VecType &v)
{
    // fill v with values [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    for (size_t i = 0; i < 10; ++i) v.push_back(i);
    // chop off the end of v, which now should be [1, 2, 3, 4, 5], but the other 5 values
    // should remain in memory
    v.resize(5);
}

template <typename VecType>
void print_vec(const char *label, VecType &v)
{
    cout << label << ": ";
    for (size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
}

int main()
{
    // instantiate a vector of each type that we're going to test
    std::vector<int> std_vec;
    bc::vector<int> boost_vec;
    bc::vector<int> boost_vec_default;

    // fill each vector in the same way
    init_vec(std_vec);
    init_vec(boost_vec);
    init_vec(boost_vec_default);

    // now resize each vector to 10 elements in ways that *should* avoid reinitializing the new elements
    std_vec.resize(10);
    boost_vec.resize(10);
    boost_vec_default.resize(10, bc::default_init);

    // print each one out
    print_vec("std", std_vec);
    print_vec("boost", boost_vec);
    print_vec("boost w/default", boost_vec_default);    
}

Compiling this with g++ 4.8.1 in C++03 mode as follows:

g++ vectest.cc
./a.out

yields the following output:

std: 0 1 2 3 4 0 0 0 0 0 
boost: 0 1 2 3 4 0 0 0 0 0 
boost w/default: 0 1 2 3 4 5 6 7 8 9

This isn't too surprising. I expect the C++03 std::vector<T> to initialize the final 5 elements with zeros. I can even convince myself why boost::container::vector<T> is doing the same (I would assume it emulates C++03 behavior in C++03 mode). I only got the effect that I wanted when I specifically ask for default initialization. However, when I rebuilt in C++11 mode as follows:

g++ vectest.cc -std=c++11
./a.out

I get these results:

std: 0 1 2 3 4 0 0 0 0 0 
boost: 0 1 2 3 4 0 0 0 0 0 
boost w/default: 0 1 2 3 4 5 6 7 8 9

Exactly the same! Which leads to my question:

Am I wrong in thinking that I should see the same results from each of the three tests in this case? This seems to indicate that the std::vector<T> interface change hasn't really had any effect, as the 5 elements added in the final call to resize() still get initialized with zeros in the first two cases.

解决方案

Not an answer, but a lengthy addendum to Howard's: I use an allocator adapter that basically works the same as Howard's allocator, but is safer since

  1. it only interposes on value-initialization and not all initializations,
  2. it correctly default-initializes.

// Allocator adaptor that interposes construct() calls to
// convert value initialization into default initialization.
template <typename T, typename A=std::allocator<T>>
class default_init_allocator : public A {
  typedef std::allocator_traits<A> a_t;
public:
  template <typename U> struct rebind {
    using other =
      default_init_allocator<
        U, typename a_t::template rebind_alloc<U>
      >;
  };

  using A::A;

  template <typename U>
  void construct(U* ptr)
    noexcept(std::is_nothrow_default_constructible<U>::value) {
    ::new(static_cast<void*>(ptr)) U;
  }
  template <typename U, typename...Args>
  void construct(U* ptr, Args&&... args) {
    a_t::construct(static_cast<A&>(*this),
                   ptr, std::forward<Args>(args)...);
  }
};

这篇关于是矢量的这种行为::调整大小(SIZE_TYPE N)下的C ++ 11和Boost.Container是否正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆