c++ - for loop bounds recalculated each iteration? -
suppose have class so:
class { public: a(const size_t m, const size_t n) : m_(m), n_(n), data_(m*n ? new double[m*n] : nullptr) {} ~a() { delete[] data_; } void foo() const { // m_*n_ evaluated each iteration? (size_t = 0; i<m_*n_; ++i) data_[i] = 0.0; // wont above? (auto& : *this) = 0.0; } double* begin() const { return data_; } double* end() const { return data_ + m_*n_; } private: size_t m_, n_; double* data_; };
since foo const , m_,n_ member variables, compiler should know these cannot change. product evaluated each time or compiler optimize away?
question 1:
// m_*n_ evaluated each iteration? (size_t = 0; i<m_*n_; ++i) data_[i] = 0.0;
answer: probably, never know. compilers getting pretty clever.
you improve odds lot declaring m_
, n_
const
members. should anyway, imho, because logic of class requires it; if m_
or n_
change, data_
needs reallocated. declaring variables const
tells compiler if can't see definitions of member functions of class, allowed assume m_
, n_
don't change.
question 2:
(auto& : *this) = 0.0;
in case, end value not recomputed, definition. how range statement defined.
in general, there considerable difference between:
(auto p = container.begin(), lim = container.end(); p != lim; ++p) { ... }
and
(auto p = container.begin(); p != container.end(); ++p) { ... }
in first case, assumption container not modified during loop, since modification invalidate iterators (such lim
iterator). (there container types not true. container types, modification should avoided during loops.)
in second case, limit value computed every time, if container modified there no problem. @ least, there no problem end test. still need ensure p
cannot invalidated, , container types -- unordered maps , sets, example -- sequence of elements can altered modification, adding new element might cause elements missing iteration.
the range syntax for ( variable : expression)
explicitly defined translated first of above iteration styles, limit computed once @ beginning of iteration, , consequently mutations might invalidate limit iterator result in undefined behaviour.
in cases, should avoid such mutations , should use range syntax or equivalent style. there applications in recomputing limit each time appropriate. best example of such use-case worklist, can modeled std::deque
:
for (auto work = workqueue.begin(); work != workqueue.end(); ++work) { /* ... */ if (some_condition) { work_queue.emplace_back(work_item); } /* ... */ }
that's common style in graph algorithms, example.
Comments
Post a Comment