Namespaces
Variants

Talk:cpp/container/vector/vector

From cppreference.com

I think that the time complexity of ctor (4) is wrong. During construction, a emplace_back() or push_back() will be called while iterating. 175.156.147.173 19:55, 13 December 2013 (PST)

The standard requires exactly N constructors of T and no reallocations for this constructor (given iterators that are at least ForwardIterators). You are right in that this page is missing the special case for InputIterators that aren't ForwardIterators. --Cubbi (talk) 00:25, 14 December 2013 (PST)

length_error

std::vector ctors may throw std::length_error. This isn't covered adequately. Even if the implementation manages to throw length_error from within the allocator, I'd rather expect bad_alloc in that case. Heifreblo (talk) 00:52, 19 August 2018 (PDT)

Move constructor guarantees

The vector move constructor (6) seems to be incorrect from my understanding, as the standard does not say anywhere about guaranteeing that it should be empty after a move. I have seen an argument saying that it must be due to the complexity requirement but a vector of trivially destructible objects may be moved in constant time without doing a pointer swap or whatever which usually would leave the other empty. Is there something I'm missing which does give it that guarantee or is it wrong?

--Presentfactory (talk) 17:28, 24 August 2018 (PDT)

See the discussion at Template_talk:cpp/container/constructor --Cubbi (talk) 18:10, 24 August 2018 (PDT)

Invalidation of iterators

After container move construction (overload (6)), references, pointers, and iterators (other than the end iterator) to other remain valid, but refer to elements that are now in *this. The current standard makes this guarantee via the blanket statement in §23.2.1[container.requirements.general]/12, and a more direct guarantee is under consideration via LWG 2321.

Is it not more accurate to say [container.requirements.general]/12 does not make such a guarantee, and that's why there is LWG 2321? LWG 2321 itself says "I do not believe that blanket language like [current /12] is applicable."

--Lack (talk) 12:04, 15 October 2018 (PDT)

/12 makes the guarantee for all member functions. STL in LWG2321 doesn't believe that the guarantee applies to move special member functions because "The guarantees need several exceptions", presumably the exceptions listed in the proposed wording. Cubbi (talk) 12:21, 15 October 2018 (PDT)
I don't read LWG2321 as proposing to add exceptions to an existing guarantee. There is no guarantee for move constructors and assignment operators before LWG2321. It says that if they were to add one, it would need exceptions and not use the same language as /12. (I did misread the "is applicable" part; it is just commenting on which wording would be applicable.)
The reason exceptions are unavoidable has to do with allocators, as discussed on SO. My guess for why the language of /12 does not apply is that a = move(b) is not invoking a member function of b. --Lack (talk) 13:16, 15 October 2018 (PDT)
the language of /12 definitely applies to move constructors and assignment operators (wording "invoking a container member function") as well as to b in a = move(b) (wording: "passing a container as an argument to a library function"). The issue is that the wording appears to be defective. --Cubbi (talk) 13:23, 15 October 2018 (PDT)
Do you mean vector::operator=(vector&&) counts as a "library function"? (Surely std::move does not invalidate anything, and is irrelevant.) My guess aside, it seems clear that the authors of LWG2321 think there is no guarantee ("move constructors and move assignment operators aren't given similar invalidation guarantees"), and that such a guarantee would be impossible to satisfy in general.
Even if you are right that /12 gives a guarantee but is defective, I think this reference should be edited to note the defect. It is helpful to know that iterators might be invalidated in reality, and to know the proposed wording in LWG2321. --Lack (talk) 15:37, 15 October 2018 (PDT)
in order for iterators to have the chance of being invalidated "in reality", one of the three current implementations of the C++ standard library (libstdc++, libc++, MSVC) needs to have misinterpreted the intent of this subclause (and also needs to have missed the clarification of the intent provided by the issue) It's easy to examine. --Cubbi (talk) 19:09, 15 October 2018 (PDT)
OK, I concede no implementation actually invalidates on move constructor. I also see the page on operator= does describe the allocator issue where it's more relevant, which completely satisfies my "wording in LWG2321" suggestion -- I'm sorry I missed it. I am still confused by the sentence I originally bolded, "the current standard makes this guarantee via the blanket statement..." If /12 makes the guarantee, doesn't it imply vector(vector&&, const Allocator&) does not invalidate? --Lack (talk) 22:03, 15 October 2018 (PDT)
The standard says X. It may be defective, but it still says X as of now. Maybe I should write a PR for 2321... T. Canens (talk) 15:47, 16 October 2018 (PDT)

Move constructor guarantees

The standard does NOT guarantee that the moved vectror will be "empty()", and it should not be said so on this site if you care about following the standard, no matter what you think about what "should" be implemented.

I was burned by this statement using a crosscompiler for ARM.

- Kasper G.

Did you file a bug report with the vendor? --Cubbi (talk) 19:42, 18 December 2020 (PST)

Braces vs. parentheses initialization ambiguity

Is it worth adding something about the pitfall of std::vector<int>{8} being a one-element vector, compared to std::vector<int>(8) being a 8-sized one? I am not confident enough to word it correctly though.

The list initialization rules imply that when both initializer list constructor (10) and count constructors (3,4) are viable, the former is chosen. Therefore, when using the initializer-list syntax of initialization, constructor (10) is chosen: std::vector<int>{ 3 } results in a vector with a single element (value { 3 }), and std::vector<int>{ 2, 0 } results in a vector with two elements ({ 2, 0 }). The outcome is noticeably different when using the expression-list initialization syntax, where std::vector<int>(3) yields a three-element vector { 0, 0, 0 }(until C++11)with unspecified values(since C++11) using constructor (4), and std::vector<int>(2, 0) a two-element vector { 0, 0 } using constructor (3).

68.65.161.172 11:48, 16 February 2022 (PST)

Gotta be on your toes when using list initialisation syntax. The problem exists more generally than vector, so not sure it makes too much sense to write a pitfall note here, maybe over in the list initialization page, in fact it is noted in the example there. Could perhaps be noted in an example here too, but don't think it warrants so much text to describe the issue.
Also std::vector<int>(3) makes a three-element vector of zeros in all C++ versions (default inserted means value initialised, which means zero initialised for scalar types). In general, stdlib containers don't like holding uninitialised values because it would be copying that container emit undefined behaviour --Ybab321 (talk) 03:04, 17 February 2022 (PST)
I think it's worth a brief note, being a common issue programmers run into. Drafted one now, feel free to edit further --Cubbi (talk) 08:34, 17 February 2022 (PST)
Possible further bad behaviour includes
#include <string>
#include <vector>
int main() {
    std::vector<std::string> z(1); // Makes a vector of strings with size 1
    std::vector<std::string> y(0); // Makes a vector of strings with size 0
    std::vector<std::string> x{1}; // Makes a vector of strings with size 1
//  std::vector<std::string> w{0}; // Error: tries to construct {string(0)}

    std::vector<bool> v(1, false); // Makes a vector of bools with size 1 {false}
    std::vector<bool> u{1, false}; // Makes a vector of bools with size 2 {true, false}

    std::vector src{1, 2, 3}; // Vector of ints with size 3 {1, 2, 3}
    std::vector t(begin(src), end(src)); // Vector of ints with size 3 {1, 2, 3}
    std::vector s{begin(src), end(src)}; // Vector of std::vector<int>::iterator with size 2
}
--Ybab321 (talk) 09:41, 17 February 2022 (PST)

Capacity guarantees?

Are there any guarantees about the capacity of the constructed vector (beyond having adequate capacity for their .size() and not allocating if they are `noexcept`)? As in, if I construct with a dynamic size of zero, is the capacity zero? Is the capacity guaranteed to always equal the size? BenFrantzDale (talk) 09:42, 13 July 2023 (PDT)

I think zero capacity is implicitly guaranteed for the default-constructed vector since its C++17's noexcept signature, but capacity of a vector constructed with some initial values has no reason to match its size. --Cubbi (talk) 12:34, 13 July 2023 (PDT)