Is this behavior of vector::resize(size_type n) under C++11 and Boost.Container correct?

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)...);
  }
};

There is a small functional difference with the C++11 resize signatures, but your test will not expose it. Consider this similar test:

#include <iostream>
#include <vector>

struct X
{
    X() {std::cout << "X()\n";}
    X(const X&) {std::cout << "X(const X&)\n";}
};

int
main()
{
    std::vector<X> v;
    v.resize(5);
}

Under C++03 this prints:

X()
X(const X&)
X(const X&)
X(const X&)
X(const X&)
X(const X&)

But under C++11 it prints:

X()
X()
X()
X()
X()

The motivation for this change is to better support non-copyable (move-only) types in vector. Most of the time, including in your case, this change makes no difference.

There is a way to accomplish what you want in C++11 with the use of a custom allocator (which your compiler may or may not yet support):

#include <iostream>
#include <vector>

using namespace std;

template <class T>
class no_init_alloc
    : public std::allocator<T>
{
public:
    using std::allocator<T>::allocator;

    template <class U, class... Args> void construct(U*, Args&&...) {}
};


template <typename VecType>
void init_vec(VecType &v)
{
    // fill v with values [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    v.resize(10);
    for (size_t i = 0; i < 10; ++i) v[i] = i;  // Note this change!!!
    // 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()
{
    std::vector<int, no_init_alloc<int>> std_vec;
    init_vec(std_vec);
    std_vec.resize(10);
    print_vec("std", std_vec);
}

Which should output:

std: 0 1 2 3 4 5 6 7 8 9 

The no_init_alloc simply refuses to do any initialization, which is fine for int, leaving it with an unspecified value. I had to change your init_vec to use assignment to initialize instead of using construction though. So this can be dangerous / confusing if you are not careful. However it does avoid doing unnecessary initialization.


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.

No, not really. Having a container of elements that are not actually constructed does not make sense. I'm not sure what you expected to see other than zeroes. Unspecified/uninitialised elements? That's not what value-initialisation means.

If you need N elements, then you should have N properly-constructed elements, and that is what std::vector::resize does. Value-initialisation will zero-initialise an object with no default constructor to invoke, so really it's the opposite of what you seem to want, which is less safety and initialisation rather than more.

I suggest that what you're really after is std::vector::reserve.

This seems to indicate that the std::vector<T> interface change hasn't really had any effect

It certainly has an effect, just not the one you're looking for. The new resize overload is for convenience so that you don't have to construct your own temporary when default- or even value-initialisation is all you need. It isn't a fundamental change to how containers work, which is that they always hold valid instances of types.

Valid but in an unspecified state if you move from them!