When a C++ function accepts an std::vector argument, the usual pattern is to pass it by const reference, such as:
int sum2(const std::vector<int> &v)
{
int s = 0;
for(size_t i = 0; i < v.size(); i++) s += fn(v[i]);
return s;
}
I believe that this code results in double dereferencing when the vector elements are accessed, because the CPU should first dereference v to read the pointer to the first element, which pointer needs to be dereferenced again to read the first element. I would expect that it would be more efficient to pass a shallow copy of the vector object on the stack. Such shallow copy would encapsulate a pointer to the first element, and the size, with the pointer referencing the same memory area as the original vector does.
int sum2(vector_ref<int> v)
{
int s = 0;
for(size_t i = 0; i < v.size(); i++) s += fn(v[i]);
return s;
}
Similar performance, but much less convenience could be achieved by passing a random access iterator pair. My question is: what is flawed with this idea? I expect that there should be some good reason that smart people accept to pay the performace cost of vector reference, or deal with the inconvenience of iterators.
Edit: Based on the coments below, please consider the situation if I simply rename the suggested vector_ref class to slice or range. The intention is to use random-access iterator pairs with more natural syntax.
I believe that this code results in double dereferencing when the vector elements are accessed
Not necessarily. Compilers are pretty smart and should be able to eliminate common subexpressions. They can see that the operator [] doesn't change the 'pointer to the first element', so they have no need make the CPU reload it from memory for every loop iteration.
What's wrong with your idea is that you already have two perfectly good solutions:
Pass the vector as is, either by value (where the compiler will often eliminate the copy), or by (const) reference, and trust the compiler to eliminate the double indirection, or
Pass an iterator pair.
Of course you can argue that the iterator pair is "less natural syntax", but I disagree. It is perfectly natural to anyone who's used to the STL. It is efficient, and gives you exactly what you need to work with the range, using std algorithms or your own functions.
Iterator pairs are a common C++ idiom, and a C++ programmer reading your code will understand them without a problem, whereas they're going to be surprised at your home-brewed vector wrappers.
If you're really paranoid about performance, pass the pair of iterators. If the syntax really bothers you, pass the vector and trust the compiler.
What is flawed with this idea?
Simple: It's premature optimization. Alternatives: Accept a vector<int> const& and use iterators or pass iterators directly to the function.
You're right that there's an extra indirection here. It's conceivable (though it would be surprising) if the compiler (with the help of link-time code generation) optimized it away.
What you've proposed is sometimes called slicing, and it's used extensively in some situations. Though, in general, I'm not sure it's worth the dangers. You have to be very careful about invaliding your slice (or someone else's).
Note that if you used iterators for the loop instead of indexing, then you'd deref the reference only a couple times (to call begin() and end()) rather than n times (to index into the vector).
int sum(const vector<int> &v)
{
int s = 0;
for (auto it = v.begin(); it != v.end(); ++it) {
s += fn(*it);
}
return s;
}
(I'm assuming the optimizer will hoist the end() calls out of the loop. You could do it explicitly to be certain.)
Passing a pair of iterators instead of the container itself seems like the STL idiom. That would give you more generality, as the type of container can vary, but so can the number of dereferences needed.
Pass by value unless you're certain passing by reference improves performances.
When you pass by value, copy elision may occur which will result in similar if not better performances.
Dave wrote about it here:
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
There is no double dereferencing because the compiler will probably pass the real pointer to the vector as the argument and not a pointer to a pointer. You can simply try this out and check the disassembly view of your IDE for what is actually going on behind the scenes:
void Method(std::vector<int> const& vec) {
int i = vec.back();
}
void SomeOtherMethod() {
std::vector<int> vec;
vec.push_back(1);
Method(vec);
}
What happens here? The vector is allocated on the stack. The first push back is translated to:
push eax // this is the constant one that has been stored in eax
lea ecx,[ebp-24h] // ecx is the pointer to vec on the stack
call std::vector<int,std::allocator<int> >::push_back
Now we call Method(), passing the vector const&:
lea ecx,[ebp-24h]
push ecx
call Method (8274DC0h)
Unsurprisingly, the pointer to the vector is passed as references are nothing but permanently dereferenced pointers. Now inside Method(), the vector is accessed again:
mov ecx,dword ptr [ebp+8]
call std::vector<int,std::allocator<int> >::back (8276100h)
The vector pointer is taken directly from the stack and written to ecx.
Related
Simple theoretical question: would a simple pointer be a valid iterator type for std::vector?
For other containers (e.g. list, map), that would not be possible, but for std::vector the held data is guaranteed to be contiguous, so I see no reason why not.
As far as I know, some implementations (e.g. Visual Studio) do some safe checks on debug build. But that is in UB territory, so for well defined behavior I think there is no difference.
Apart for some checks ("modifying" undefined behavior), are there any advantages of using a class instead of a simple pointer for vector iterators?
would a simple pointer be a valid iterator type for std::vector?
Yes. And also for std::basic_string and std::array.
are there any advantages of using a class instead of a simple pointer for vector iterators?
It offers some additional type safety, so that logic errors like the following don't compile:
std::vector<int> v;
int i=0;
int* p = &i;
v.insert(p, 1); // oops, not an iterator!
delete v.begin(); // oops!
std::string s;
std::vector<char> v;
// compiles if string and vector both use pointers for iterators:
v.insert(s.begin(), '?');
std::array<char, 2> a;
// compiles if array and vector both use pointers for iterators:
v.erase(a.begin());
Yes, it can be T*, but that has the slightly annoying property that the ADL-associated namespace of std::vector<int>::iterator is not std:: ! So swap(iter1, iter2) may fail to find std::swap.
A food for thought - an iterator class can also be implemented by the terms of indexes instead of pointers
of course, when a vector reallocates, all the pointers , references and iterators become invalidated.
but at least for iterators, that doesn't have to be the case always, if the iterator holds an index + pointer to the vector, you can create non-reallocation-invalidated iterators that simply returns (*m_vector)[m_index]. the iterator is invalid when the vector dies out, or the index is invalid. in other words, the iterator is invalid only if the term vec[i] is invalid, regardless of reallocations.
this is a strictly non standard implementation of a vector iterator, but non the less an advantage to class based iterator rather than raw pointer.
also, UB doesn't state what should happen when an invalid iterator is being dereferenced. throwing an exception or logging an error fall under UB.
that means that an iterator which does bound checking is significantly slower, but for some cases where speed is not important, "safe but slow iterator" may have more advantages than "unsafe but fast iterator"
at a time, I created a pointer point to a std::vector, then I did some push_back, reserve, resize operation to that vector, after such operations, is it safe to compare the pointer to the address of that vector to check whether the pointer point to that vector, because there might be some re-allocation of memory.
for example
std::vector<int> vec;
vector<int>* pVec = &vec;
vec.reserve(10000);
assert(pVec == &vec);
vec = anotherVec;
assert(pVec == &vec);
what is more, is it safe to compare a pointer to the first value of vector?
for example:
std::vector<int> vec(1,0);
int* p = &vec[0];
// some operation here
assert(p == &vec[0]);
As I tested by myself, it seems that the first situation is safe, while the second is not, but I can't be sure.
std::vector<int> vec;
vector<int>* pVec = &vec;
vec.reserve(10000);
assert(pVec == &vec);
is safe.
std::vector<int> vec(1,0);
int* p = &vec[0];
// some operation here
assert(p == &vec[0]);
is not safe.
The first block is safe since the address vec will not change even when its contents change.
The second block is not safe since the address of vec[0] may change; for example when the vec resizes itself — e.g, when you push_back elements to it.
it seems that the first situation is safe, while the second is not
That's right. In the first "situation", the vec object itself stays wherever it is in memory regardless of the reserve call, which might move the managed elements to another area of dynamic memory. It's because elements can be moved that the pointers may not compare equal in the second scenario.
The second situation is safe as long as no relocation takes place. If you know the size you will need in advance and use reserve() before you get the pointer it is perfectly safe and you save a little bit of performance (one less level of indirection).
However, any addition with push_back() for example might go beyond the allocated space and invalidate your pointer. std::vector is optimized and will try to allocate more memory at the same position if possible (since it saves copying data around) but you cannot be sure of that.
For that matter, instead of taking a pointer you could take an iterator because an iterator on a vector behaves exactly like a pointer (and has no performance impact) with more type safety.
vector<int>* pVec = &vec; operates on the address of the std::vector<int> object which is valid till scope.
vec = anotherVec; does not change the address of the vec because of here the operator = of std::vector is called.
So, both assert(pVec == &vec); is successfully passed through.
In the case int* p = &vec[0]; it depends: see Iterator invalidation.
The first case is indeed safe as there is no danger of the vector object's address changing. The second case is safe as long as no reallocation happens (reallocations can be traced using the std::vector::capacity member function), otherwise it's either undefined or implementation-defined depending on the version of the language. For more information consult this answer. since the same restrictions apply in that case.
I'm looking at the implementation of std::vector in libc++ and I noticed that it internally keeps three pointers (one to the begin, one the end, and one to the end of the allocated memory) instead of what I'd instinctively do, i.e., one pointer to the begin and two size and capacity members.
Here is the code from libc++'s <vector> (ignore the compressed pair, I know what it means).
pointer __begin_;
pointer __end_;
__compressed_pair<pointer, allocator_type> __end_cap_;
I noticed that also other standard libraries do the same (e.g. Visual C++).
I don't see any particular reason why this solution should be faster than the other one, but I might be wrong.
So is there a particular reason the "three pointers" solution is preferred to the "pointer + sizes" one?
It's because the rationale is that performance should be optimized for iterators, not indices.
(In other words, performance should be optimized for begin()/end(), not size()/operator[].)
Why? Because iterators are generalized pointers, and thus C++ encourages their use, and in return ensures that their performance matches those of raw pointers when the two are equivalent.
To see why it's a performance issue, notice that the typical for loop is as follows:
for (It i = items.begin(); i != items.end(); ++i)
...
Except in the most trivial cases, if we kept track of sizes instead of pointers, what would happen is that the comparison i != items.end() would turn into i != items.begin() + items.size(), taking more instructions than you'd expect. (The optimizer generally has a hard time factoring out the code in many cases.) This slows things down dramatically in a tight loop, and hence this design is avoided.
(I've verified this is a performance problem when trying to write my own replacement for std::vector.)
Edit: As Yakk pointed out in the comments, using indices instead of pointers can also result in the generation of a multiplication instruction when the element sizes aren't powers of 2, which is pretty expensive and noticeable in a tight loop. I didn't think of this when writing this answer, but it's a phenomenon that's bitten me before (e.g. see here)... bottom line is, in a tight loop everything matters.
It's more convenient for implementers.
Storing size makes exactly one operation easier to implement: size()
size_t size() { return size_; }
on the other hand, it makes other harder to write and makes reusing code harder:
iterator end() { return iterator(end_); } // range version
iterator end() { return iterator(begin_ + size_); } // pointer + size version
void push_back(const T& v) // range version
{
// assume only the case where there is enough capacity
::new(static_cast<void*>(end_)) T(v);
++end_;
}
void push_back(const T& v) // pointer + size version
{
// assume only the case where there is enough capacity
::new(static_cast<void*>(begin_ + size_)) T(v);
// it could use some internal `get_end` function, but the point stil stands:
// we need to get to the end
++size_;
}
If we have to find the end anyway, we could store it directly - it's more useful than size anyway.
I would imagine it's primarily a speed thing. When iterating over the set, the generated instructions for bounds checking would simply be a compare statement with the end pointer (and maybe a load), rather than a load, an add, and a compare (and maybe another load, too).
When generating the iterators for end() and begin(), the code would also just be return pointer;, rather than return pointer + offset; for end().
These are very minor optimizations, but the standard template library is intended to be used in production code where every cycle counts.
PS: In regards to the different compilers implementing it the same way: There is a reference implementation that most (all?) of the compiler vendors base their STL implementations on. It is likely that this particular design decision is a part of the reference implementation, and is why all the implementations you looked at handle vectors this way.
I'm trying to learn some c++, to start off I created some methods to handle outputing to and reading from a console.
I'm having 2 major problems, marked in the code, manipulating/accessing values within a std::vector of strings passed in by reference.
The method below takes in a question (std string) to ask the user and a vector std strings that contain responses from the user deemed acceptable. I also wanted, in the interest of learning, to access a string within the vector and change its value.
std::string My_Namespace::My_Class::ask(std::string question, std::vector<std::string> *validInputs){
bool val = false;
std::string response;
while(!val){
//Ask and get a response
response = ask(question);
//Iterate through the acceptable responses looking for a match
for(unsigned int i = 0; i < validInputs->size(); i++){
if(response == validInputs->at(i)){
////1) Above condition always returns true/////
val = true;
break;
}
}
}
//////////2) does not print anything//////////
println(validInputs->at(0)); //note the println method is just cout << param << "\n" << std::endl
//Really I want to manipulate its value (not the pointer the actual value)
//So I'd want something analogous to validInputs.set(index, newVal); from java
///////////////////////////////////////////
}
A few additional questions:
3) I'm using .at(index) on the the vector to get the value but I've read that [] should be used instead, however I'm not sure what that should look like (validInputs[i] doesn't compile).
4) I assume that since a deep copy is unnecessary its good practice to pass in a pointer to the vector as above, can someone verify that?
5) I've heard that ++i is better practice than i++ in loops, is that true? why?
3) There should not be a significant difference using at and operator[] in this case. Note that you have a pointer-to-vector, not a vector (nor reference-to-vector) so you will have to use either (*validInputs)[i] or validInputs->operator[](i) to use the operator overload. Using validInputs->at(i) is fine if you don't want to use either of these other approaches. (The at method will throw an exception if the argument is out of the array bounds, while the operator[] method has undefined behavior when the argument is out of the array bounds. Since operator[] skips the bounds check, it is faster if you know for a fact that i is within the vector's bounds. If you are not sure, use at and be prepared to catch an exception.)
4) A pointer is good, but a reference would be better. And if you're not modifying the vector in the method, a reference-to-const-vector would be best (std::vector<std::string> const &). This ensures that you cannot be passed a null pointer (references cannot be null), while also ensuring that you don't accidentally modify the vector.
5) It usually is. i++ is post-increment, which means that the original value must be copied, then i is incremented and the copy of the original value is returned. ++i increments i and then returns i, so it is usually faster, especially when dealing with complex iterators. With an unsigned int the compiler should be smart enough to realize that a pre-increment will be fine, but it's good to get into the practice of using ++i if you don't need the original, unincremented value of i.
I'd use a reference-to-const, and std::find. Note that I also take the string by reference (it gets deep copied otherwise) :
std::string My_Class::
ask (const std::string& question, const std::vector<std::string>& validInputs)
{
for (;;) {
auto response = ask (question);
auto i = std::find (validInputs.begin (), validInputs.end (), response);
if (i != validInputs.end ()) {
std::cout << *i << '\n'; // Prints the value found
return *i;
}
}
}
Read about iterators if you don't understand the code. Of course, feel free to ask other questions if you need.
I'm not going to address points 1 and 2 since we don't know what you are doing and we don't even see the code for ask and println.
I'm using .at(index) on the the vector to get the value but I've read that [] should be used instead, however I'm not sure what that should look like (validInputs[i] doesn't compile).
Subscript access and at member function are different things. They give you the very same thing, a reference to the indexed element, but they behave differently if you pass an out-of bounds index: at will throw an exception while [] will invoke undefined behavior (as builtin arrays do). Using [] on a pointer is somewhat ugly, (*validInputs)[i], but you really should avoid pointers when possible.
I assume that since a deep copy is unnecessary its good practice to pass in a pointer to the vector as above, can someone verify that?
A deep copy is unnecessary, but so is a pointer. You want a reference instead, and a const one since I presume you shouldn't be modifying those:
ask(std::string const& question, std::vector<std::string> const& validInputs)
I've heard that ++i is better practice than i++ in loops, is that true? why?
Its true in the general case. The two operations are different, ++i increments i and returns the new value while i++ increments i but returns the value before the incrementation, which requires a temporary to be hold and returned. For ints this hardly matters, but for potentially fat iterators preincrement is more efficient and a better choice if you don't need or care for its return value.
To answer questions 1 and 2, we'll probably need more information, like: How did you initialize validInputs? What's the source of ask?
3) First dereference the pointer, then index the vector:
(*validInputs)[i]
4) References are considered better style. Especially instead of pointers which never are NULL.
5) For integers, it doesn't matter (unless you evaluate the result of the expression). For other objects, with overloaded ++ operators (iterators, for example) it may be better to use ++i. But in practice, for inline definitions of the ++ operator, it will probably be optimized to the same code.
A const int * and an int *const are very different. Similarly with const std::auto_ptr<int> vs. std::auto_ptr<const int>. However, there appears to be no such distinction with const std::vector<int> vs. std::vector<const int> (actually I'm not sure the second is even allowed). Why is this?
Sometimes I have a function which I want to pass a reference to a vector. The function shouldn't modify the vector itself (eg. no push_back()), but it wants to modify each of the contained values (say, increment them). Similarly, I might want a function to only change the vector structure but not modify any of its existing contents (though this would be odd). This kind of thing is possible with std::auto_ptr (for example), but because std::vector::front() (for example) is defined as
const T &front() const;
T &front();
rather than just
T &front() const;
There's no way to express this.
Examples of what I want to do:
//create a (non-modifiable) auto_ptr containing a (modifiable) int
const std::auto_ptr<int> a(new int(3));
//this works and makes sense - changing the value pointed to, not the pointer itself
*a = 4;
//this is an error, as it should be
a.reset();
//create a (non-modifiable) vector containing a (modifiable) int
const std::vector<int> v(1, 3);
//this makes sense to me but doesn't work - trying to change the value in the vector, not the vector itself
v.front() = 4;
//this is an error, as it should be
v.clear();
It's a design decision.
If you have a const container, it usually stands to reason that you don't want anybody to modify the elements that it contains, which are an intrinsic part of it. That the container completely "owns" these elements "solidifies the bond", if you will.
This is in contrast to the historic, more lower-level "container" implementations (i.e. raw arrays) which are more hands-off. As you quite rightly say, there is a big difference between int const* and int * const. But standard containers simply choose to pass the constness on.
The difference is that pointers to int do not own the ints that they point to, whereas a vector<int> does own the contained ints. A vector<int> can be conceptualised as a struct with int members, where the number of members just happens to be variable.
If you want to create a function that can modify the values contained in the vector but not the vector itself then you should design the function to accept iterator arguments.
Example:
void setAllToOne(std::vector<int>::iterator begin, std::vector<int>::iterator end)
{
std::for_each(begin, end, [](int& elem) { elem = 1; });
}
If you can afford to put the desired functionality in a header, then it can be made generic as:
template<typename OutputIterator>
void setAllToOne(OutputIterator begin, OutputIterator end)
{
typedef typename iterator_traits<OutputIterator>::reference ref;
std::for_each(begin, end, [](ref elem) { elem = 1; });
}
One big problem syntactically with what you suggest is this: a std::vector<const T> is not the same type as a std::vector<T>. Therefore, you could not pass a vector<T> to a function that expects a vector<const T> without some kind of conversion. Not a simple cast, but the creation of a new vector<const T>. And that new one could not simply share data with the old; it would have to either copy or move the data from the old one to the new one.
You can get away with this with std::shared_ptr, but that's because those are shared pointers. You can have two objects that reference the same pointer, so the conversion from a std::shared_ptr<T> to shared_ptr<const T> doesn't hurt (beyond bumping the reference count). There is no such thing as a shared_vector.
std::unique_ptr works too because they can only be moved from, not copied. Therefore, only one of them will ever have the pointer.
So what you're asking for is simply not possible.
You are correct, it is not possible to have a vector of const int primarily because the elements will not assignable (requirements for the type of the element contained in the vector).
If you want a function that only modifies the elements of a vector but not add elements to the vector itself, this is primarily what STL does for you -- have functions that are agnostic about which container a sequence of elements is contained in. The function simply takes a pair of iterators and does its thing for that sequence, completely oblivious to the fact that they are contained in a vector.
Look up "insert iterators" for getting to know about how to insert something into a container without needing to know what the elements are. E.g., back_inserter takes a container and all that it cares for is to know that the container has a member function called "push_back".