<ol>
<li><a href="#hl_assert">Assert Liberally</a>
<li><a href="#hl_preincrement">Prefer Preincrement</a>
+ <li><a href="#hl_avoidendl">Avoid endl</a>
<li><a href="#hl_exploitcpp">Exploit C++ to its Fullest</a>
</ol>
<li><a href="#iterators">Writing Iterators</a>
<pre>
inline Value *getOperand(unsigned i) {
- assert(i < Operands.size() && "getOperand() out of range!");
+ assert(i < Operands.size() && "getOperand() out of range!");
return Operands[i];
}
</pre>
Here are some examples:
<pre>
- assert(Ty->isPointerType() && "Can't allocate a non pointer type!");
+ assert(Ty->isPointerType() && "Can't allocate a non pointer type!");
assert((Opcode == Shl || Opcode == Shr) && "ShiftInst Opcode invalid!");
- assert(idx < getNumSuccessors() && "Successor # out of range!");
+ assert(idx < getNumSuccessors() && "Successor # out of range!");
assert(V1.getType() == V2.getType() && "Constant types must be identical!");
- assert(Succ->front()->isPHINode() && "Only works on PHId BBs!");
+ assert(isa<PHINode>(Succ->front()) && "Only works on PHId BBs!");
</pre><p>
You get the idea...<p>
The semantics of postincrement include making a copy of the value being incremented, returning it, and then preincrementing the "work value". For primitive types, this isn't a big deal... but for iterators, it can be a huge issue (for example, some iterators contains stack and set objects in them... copying an iterator could invoke the copy ctor's of these as well). In general, get in the habit of always using preincrement, and you won't have a problem.<p>
+<!-- _______________________________________________________________________ -->
+</ul><a name="hl_avoidendl"><h4><hr size=0>Avoid endl</h4><ul>
+
+The <tt>endl</tt> modifier, when used with iostreams outputs a newline to the output stream specified. In addition to doing this, however, it also flushes the output stream. In other words, these are equivalent:<p>
+
+<pre>
+ cout << endl;
+ cout << "\n" << flush;
+</pre>
+
+Most of the time, you probably have no reason to flush the output stream, so it's better to use a literal <tt>"\n"</tt>.<p>
+
+
<!-- _______________________________________________________________________ -->
</ul><a name="hl_exploitcpp"><h4><hr size=0>Exploit C++ to its Fullest</h4><ul>
public std::iterator<std::forward_iterator_tag, value_type> {
friend class container;
public:
- const value_type& operator*() const;
+ const value_type& operator*() const;
const value_type* operator->() const;
- const_iterator& operator++();
+ const_iterator& operator++();
const_iterator operator++(int);
friend bool operator==(const_iterator lhs,
const_iterator rhs);
There are normally only three member functions that need nontrivial
implementations; the rest are just boilerplate.
- const container::value_type&
+ const container::value_type&
container::const_iterator::operator*() const {
// find the element and return a reference to it
}
const container::value_type*
container::const_iterator::operator->() const {
- return &**this;
+ return &**this;
}
If there's an underlying real container, operator*() can just return a
The operator->() function is just boilerplate around a call to
operator*().
- container::const_iterator&
+ container::const_iterator&
container::const_iterator::operator++() {
// the incrementing logic goes here
return *this;
friend class container;
friend class container::const_iterator;
public:
- value_type& operator*() const;
+ value_type& operator*() const;
value_type* operator->() const;
- iterator& operator++();
+ iterator& operator++();
iterator operator++(int);
friend bool operator==(iterator lhs, iterator rhs);
friend bool operator!=(iterator lhs, iterator rhs);
friend class container;
public:
const_iterator();
- const_iterator(const iterator& i);
- const value_type& operator*() const;
+ const_iterator(const iterator& i);
+ const value_type& operator*() const;
const value_type* operator->() const;
- const_iterator& operator++();
+ const_iterator& operator++();
const_iterator operator++(int);
friend bool operator==(const_iterator lhs,
const_iterator rhs);
public std::iterator<std::bidirectional_iterator_tag, value_type> {
public:
//...
- iterator& operator--();
+ iterator& operator--();
iterator operator--(int);
//...
};
public std::iterator<std::random_access_iterator_tag, value_type> {
public:
//...
- iterator& operator+=(difference_type rhs);
- iterator& operator-=(difference_type rhs);
+ iterator& operator+=(difference_type rhs);
+ iterator& operator-=(difference_type rhs);
friend iterator operator+(iterator lhs, difference_type rhs);
friend iterator operator+(difference_type lhs, iterator rhs);
friend iterator operator-(iterator lhs, difference_type rhs);
//...
};
- container::iterator&
+ container::iterator&
container::iterator::operator+=(container::difference_type rhs) {
// add rhs to iterator position
return *this;
}
- container::iterator&
+ container::iterator&
container::iterator::operator-=(container::difference_type rhs) {
// subtract rhs from iterator position
return *this;
<address><a href="mailto:sabre@nondot.org">Chris Lattner</a></address>
<!-- Created: Tue Jan 23 15:19:28 CST 2001 -->
<!-- hhmts start -->
-Last modified: Mon Oct 1 08:17:21 CDT 2001
+Last modified: Wed Apr 23 11:20:49 CDT 2003
<!-- hhmts end -->
</font>
</body></html>