C++语言99个常见编程错误 常见错误7:无视基础语言的精妙之处

本文探讨了C++软件工程师常忽视的基础语言特性及其巧妙应用,包括条件运算符、索引运算符、case语句标签等,并通过具体示例展示了如何利用这些特性优化代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常见错误7:无视基础语言的精妙之处
  大多数C++软件工程师都自信满满地认为iziji对所谓C++的“基础语言”,也就是C++继承
自C语言那部分了如指掌。 实际情况是,即使经验丰富的C++软件工程师有时也会对最基础
的C/C++语句和运算符的某些妙用一无所知。
  很多软件工程师都把“如果条件运算符表达式的两个选择结果都是左值,那么这个表达式本身
就是个左值”这回事抛在脑后了。
  C++代码的很多上下文(比如构造函数的成员初始化列表,或抛出异常时的throw表达式,等等),
除了表达式别无选择。
  此内建的索引运算符只是对于某些指针算术和反引用运算符的一种简写法。
  case语句的标签必须是整形常量性的表达式。换句话说,编译器必须能在编译时就算出这些
表达式的值来。

  switch语句的平凡语法暗示着我们能够把语句块写成比上面的例子更结构化的形式。


bool.cpp
#include <iostream>

typedef unsigned short Bits;

inline Bits repeated( Bits b, Bits m )
	{ return b & m & (b & m)-1; }


void dowop1( Bits options ) {
	int ctr = 0;
	for( int i = 0; i < 8; ++i )
	    if( options & 1<<(8+i) )
	        if( ctr++ ) {
	            std::cerr << "Too many options selected" << std::endl;
	            break;
	        }
}

void dowop2( Bits options ) {
	if( repeated( options, 0XFF00 ) )
	    std::cerr << "Too many options selected" << std::endl;
}

void boolTest() {
	std::cout << "===  bool test  ===" << std::endl;
	Bits opts[] = { 0x0000, 0x1000, 0x1011, 0x2100, 0xf000 };
	for( int i = 0; i < sizeof(opts)/sizeof(opts[0]); ++i ) {
		std::cerr << "Options: " << std::hex << opts[i] << std::endl;
		dowop1( opts[i] );
		dowop2( opts[i] );
	}
}

iter.cpp
#include <iostream>

class Node;
class Preorder;
class Postorder;

class NaryTree {
  public:
	int count()
		{ return size; }
  public:
	Node *root;
	int size;
};

typedef short Index;

class Node {
  public:
	Index parent;
	Index sibling;
	Index lchild;
	// other members...
	int value;
	
	friend class Preorder;
	friend class Postorder;
};

class Preorder {
  public:
	Preorder( NaryTree &t )
		: cur( t.root ), end( t.root+t.count()-1 ) {}
	bool next();
	Node *get()
		{ return cur; }
  private:
	Node *cur, *end;
};

inline bool
Preorder::next() {
	return cur == end
		? 0
		: (++cur, 1);
}

class Postorder {
  public:
	Postorder( NaryTree &t )
		: cur( t.root ), pc( START )
		{ next(); }
	bool next();
	Node *get()
		{ return cur; }
  private:
	Node *cur;
	enum {
		START,
		LEAF,
		INNER,
		DONE
	} pc;
	bool parent()
		{ return cur->parent ? (cur+=cur->parent, true) : false; }
	bool sibling()
		{ return cur->sibling ? (cur+=cur->sibling, true) : false; }
	bool lchild()
		{ return cur->lchild ? (cur+=cur->lchild, true) : false; }
};

//对于基础语言的边角部分的理解,有时候相当有用。switch语句的性质,在C++编译器中
//做出了一个复杂数据结构内部迭代的有效实现
bool
Postorder::next() {
   switch( pc )
   case START:
   while( true )
      if( !lchild() ) {
         pc = LEAF;
         return true;
   case LEAF:
         while( true )
            if( sibling() )
               break;
            else
               if( parent() ) {
                  pc = INNER;
                  return true;
   case INNER:    ;
               }
               else {
                  pc = DONE;
   case DONE:     return false;
               }
      }
   return true; // will never be executed
}

void iterTest() {
	using namespace std;
	
	cout << "===  iter test  ===" << endl;
	
	Node tree[5] = {
			{ 0,0,1, 101 },
			{-1,3,1, 102 },
			{-1,1,0, 103 },
			{-2,0,0, 104 },
			{-4,0,0, 105 }
		};
	NaryTree n;
	n.root = tree;
	n.size = 5;
	
	cout << "Preorder: ";
	Preorder pre(n);
	do {
		cout << pre.get()->value << ' ';
	} while( pre.next() );
	cout << endl;
	
	cout << "Postorder: ";
	Postorder post(n);
	do {
		cout << post.get()->value << ' ';
	} while( post.next() );
	cout << endl;
}

main.cpp
// Note: quick hack to run tests.  Not a good coding practice!
extern void iterTest();
extern void boolTest();
#include<iostream>
int main() {
	boolTest();
	iterTest();
	getchar();
	return 0;
}


输出
===  bool test  ===
Options: 0
Options: 1000
Options: 1011
Options: 2100
Too many options selected
Too many options selected
Options: f000
Too many options selected
Too many options selected
===  iter test  ===
Preorder: 101 102 103 104 105
Postorder: 103 104 102 105 101  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值