Why isn't there an operator[] for a std::list?
Retrieving an element by index is an O(n) operation for linked list, which is what std::list
is. So it was decided that providing operator[]
would be deceptive, since people would be tempted to actively use it, and then you'd see code like:
std::list<int> xs;
for (int i = 0; i < xs.size(); ++i) {
int x = xs[i];
...
}
which is O(n^2) - very nasty. So ISO C++ standard specifically mentions that all STL sequences that support operator[]
should do it in amortized constant time (23.1.1[lib.sequence.reqmts]/12), which is achievable for vector
and deque
, but not list
.
For cases where you actually need that sort of thing, you can use std::advance
algorithm:
int iter = xs.begin();
std::advance(iter, i);
int x = *iter;
Why doesn't `std::initializer_list` provide a subscript operator?
According to Bjarne Stroustrup in Section 17.3.4.2 (p. 497) of The C++ Programming Language, 4th Edition:
Unfortunately, initializer_list doesn't provide subscripting.
No further reason is given.
My guess is that it's one of these reasons:
- it's an omission, or
- because the initializer_list class is implemented with an array and you'd have to do bounds checking to provide safe access, it could more easily be used unsafely if that interface was provided, or
- to be consistent with the std algorithms iteration paradigm, or
- because initializer_lists are, by their nature, ad-hoc, there's more room for error by addressing them directly
2 and 4 sound kind of weak. as does 3. My money's on 1.
Subscript a std::list
The standard library only provides the subscript operator when it has O(1) runtime.
For std::list
, the library requires you to get an iterator and use std::advance
to acknowledge the performance hit.
no match for operator '=' (std::arrayT, 3 and std::initializer_listT)
Why can't I initialize
std::array
with initializer list in such a way?
Braced-init-list and std::initializer_list
are not the same thing. (Even std::initializer_list
could be constructed from braced-init-list.) std::array
is an aggregate and could be aggregate-initialized or assigned by braced-init-list as
std::array<int, 3> a = {1, 2, 3};
a = {4, 5, 6}; // convert {4, 5, 6} to std::array then assign to a
Note that both {1, 2, 3}
and {4, 5, 6}
are braced-init-list but not std::initializer_list
.
std::array
can't be initialized (or assigned) from an std::initializer_list
; its constructors and assignment operator are implicitly-defined and doesn't have such constructor or assignment operator taking std::initializer_list
.
std::initializer_list<int> l = {1, 2, 3};
std::array<int, 3> a = l; // doesn't work
a = l; // doesn't work
Why is there no [] operator for std::shared_ptr?
std::unique_ptr
only defines operator[]
in a specialization for arrays: std::unique_ptr<T[]>
. For non-array pointers, the operator[] doesn't make much sense anyways (only [0]
).
Such a specialization for std::shared_ptr
is missing (in C++11), which is discussed in the related question: Why isn't there a std::shared_ptr<T[]> specialisation?
You should not use a non-array smart pointer with array allocation, unless you provide a custom deleter. In particular, unique_ptr<int> p = new int[10]
is bad, since it calls delete
instead of delete[]
. Use unique_ptr<int[]>
instead, which calls delete[]
. (And this one implements operator[]
). If you're using shared_ptr
to hold a T[]
, you need to use a custom deleter. See also shared_ptr to an array : should it be used? -- but it doesn't provide operator[]
, since it uses type erasure to distinguish between array and non-array (the smart pointer type is independent of the provided deleter).
If you wonder why there is no shared_ptr
specialization for arrays: that was a proposal, but wasn't included in the standard (mainly since you can work around by writing ptr.get() + i
for ptr[i]
).
Why isn't the [] operator const for STL maps?
For std::map
and std::unordered_map
, operator[]
will insert the index value into the container if it didn't previously exist. It's a little unintuitive, but that's the way it is.
Since it must be allowed to fail and insert a default value, the operator can't be used on a const
instance of the container.
http://en.cppreference.com/w/cpp/container/map/operator_at
No match operators[]
Error messages like no match for
mean, that either the method or operator isn't there at all, or there is such a method, but with different parameter types.
Looking at std::list
, you can see, that this is the first case, no operator[]
for std::list
can be found.
Just in case, v[1]
is not the first element in the list, but v[0]
is. Also v[n]
is not the last element.
And if the intention of the code is to calculate the sum of i * min(first, last)
, you might try using std::list::front()
and std::list::back()
instead
for (long long i = 1; i <= n; ++i) {
if (v.front() > v.back()) {
res += i * v.back();
v.pop_back();
} else {
res += i * v.front();
v.pop_front();
}
}
If you want or must use operator[]
anyway, I would rather use std::deque
. This container allows both random access (operator[]
) and also provides methods pop_back()
and pop_front()
.
Error: no match for operator[]. While comparing int to int in listint,
There are two problems:
std::list
does not have an indexing operation.- A range-based loop iterates over a container's elements, not its indices.
You should almost never use std::list
- std::vector
is almost always the appropriate alternative - and your loop should look like this:
for (auto& element: myBinaryList){
if (element == 1){
element = 0;
}
}
Why isn't vector::operator[] implemented similar to map::operator[]?
Quite simply: Because it doesn't make sense. What do you expect
std::vector<int> a = {1, 2, 3};
a[10] = 4;
to do? Create a fourth element even though you specified index 10? Create elements 3 through to 10 and return a reference to the last one? Neither would be particularily intuitive.
If you really want to fill a vector with values using operator[]
instead of push_back
, you can call resize
on the vector to create the elements before settings them.
Edit: Or, if you actually want to have an associative container, where the index is important apart from ordering, std::map<int, YourData>
might actually make more sense.
Related Topics
How to Effectively Kill a Process in C++ (Win32)
Replace Multiple Spaces with One Space in a String
How to Use Libraries Compiled with Mingw in Msvc
Openmp: What Is the Benefit of Nesting Parallelizations
Is There a C++ Iterator That Can Iterate Over a File Line by Line
How to Declare Constexpr Class in a Header and Define It in a Separate .Cpp File
Legal to Overwrite Std::String's Null Terminator
How to Avoid Entering Library's Source Files While Debugging in Qt Creator with Gdb
C++11 Operator"" with Double Parameter
<Random> Generates Same Number in Linux, But Not in Windows
Displaying Svg in Opengl Without Intermediate Raster
Difference Between A* Pa = New A; and A* Pa = New A();
Creating a Thread Pool Using Boost
Weird Msc 8.0 Error: "The Value of Esp Was Not Properly Saved Across a Function Call..."
How Can This Structure Have Sizeof == 0