??xml version="1.0" encoding="utf-8" standalone="yes"?>
在C/C++?变量?qing)函数的定义一般都是在.h/.hpp文g中说明原?而在对应?c/.cpp文g中来q行实现.
q种情况?头文件最l是l用户用的,以便让用户了解有哪些接口可以使用;?c/.cpp文g是开发者用的,以便让其它开发h员了解它的实现逻辑.因此q两个文件中肯定都是需要详l的注释??h/.hpp文g?主要说明函数的用方?如参数的意义,q回值的定义{??c/.cpp文g?主要说明函数的实现逻辑{?
不知道上面的做法是否合?请大家指?
另外,大家在实际编E过E中是如何做?
事实?我自己在实践q程中却L偏向于把注释写到一个地?或者注释原?或者注释实?前者比较多),甚至q脆两边都写一L(fng)(但这L(fng)话内容经怼(x)不一?.q样的方法让我在~程q程中吃?yu)了苦头?
]]>C++~码规范
一、组l与{略问题
If builders built buildings the way programmers wrote programs, then the
在C和C++的主要传l中,我们认ؓ(f)是一U零基础的习(fn)?W?条是一个根本的指示,它涵盖了~码规范中我们认为是最基本的徏?
first woodpecker that came along would destroy civilization.
在这介绍性的一节的其余部分?我们_ֿ选取了其中的量问题加以阐述,q些大多与编码本w无直接关系,但却是写出可靠代码的基本工具和技?
在这一节中我们认ؓ(f)最有h(hun)值的是第0条不要因失?(?知道什么不需要规范化.)
0. 不要因小失大. (?知道什么不需要规范化.)
摘要
仅说必要的话:不要坚持个h品味或陈旧的?fn)?
讨论
真只是个人品味且不媄响正性或可读性的l论不属于编码标?M专业E序员可以很Ҏ(gu)地读写稍微不同于他所?fn)惯的格式的代?
在每个源文g甚至每个工程中都要用一致的格式,因ؓ(f)在几U不同编码风格的代码片段中蟩转是很不协调?但是不要企图在不同项目或公司中坚持一致地格式.
下面是几条通用的结?q里重要的不是去制定规则,而只是要保持与你l护的文件的风格的一?
不必明确指定要羃q多?但要~进以突出结?用你喜欢的Q意数量的I格~进,但至要在同一文g中保持一?
不必保持特定的行长度,但要保持行具有可L?用你喜欢的Q意长度的行长,但不要太长了.研究表明十个单词以内的宽度对眼睛跟踪是最理想?
不要q度制定命名规则,但要用一致的命名U定:仅有两点必须要做?a)决不?隐秘?名称,也即以一个下划线开头或包括双下划线的名U?以及(qing)b)L用字母全部大写的单词命名宏ƈ且决不要考虑定义一个常用或~写单词的宏(包括常用模板参数,比如T和U;?define T anything定义M东西是极其不好的做法).此外,要用一致的有意义的名称,q按照文件或模块的约?(若你不能军_你自q命名U定,试试q种方式Q以各单词首字母大写方式命名cR函数和枚D(LikeThis);命名变量时在前者基上小写第一个单词的首字?likeThis);命名U有成员变量时在前者方式之后再加一个下划线(linkThis_);以全大写q用一个下划线q接各单词的方式命名?LINK_THIS).)
不要规定注释的风?除非有工兯析特定格式的注释生成文档),但要写有用的注释:如果可以的话以代码来代替注释(?a href="#item16">W?6?/a>).不要在注释中重复代码;它们不能被同步维?要写解释Ҏ(gu)和基本原理的启发性的注释.
最?不要试图坚持陈旧的规??a href="#0_3">??a href="#0_4">?),即它们曑֜旧编码规范出现过.
例子
void using_k_and_r_style() {
M专业E序员都可以不费力地d上面所列的M一U风格的代码.但要保持一致?不要随意的或以晦涩的嵌套方式攄括号,试着去遵循各文g中已有的风格.在本书中,我们的括h意识的在排版的约束中以最好的可读性的来放|?
// K&R风格
}
void putting_each_brace_on_its_own_line()
{
// 括号独占一?br>}
void or_putting_each_brace_on_its_own_line_indented()
{
// 括号独占一行ƈ~进
}参?/h3>
[BoostLRG] · [Brooks95] $12 · [Constantine95] $29 · [Keffer95] p. 1 ·
[Kernighan99] $1.1, $1.3, $1.6-7 · [Lakos96] $1.4.1, $2.7 · [McConnell93]
$9, $19 · [Stroustrup94] $4.2-3 · [Stroustrup00] $4.9.3, $6.4, $7.8, $C.1
· [Sutter00] $6, $20 · [SuttHysl01]1. 以高警告U别q净地编?/h2>
摘要
警告铭C?使用你的~译器的最高警告?要求q净(无警?的构?理解全部的警?q过修改代码消除警告,而不是通过降低警告U别.
讨论
~译器是你的好朋?若它׃一个特定的l构而发Z个警?通常你的代码含有潜在的问?
成功构徏应该是干净?无警告的).如若不是q样,你将?x)很快养成快速浏览输出结果的?fn)?q而你错q真正的问题.(?a href="#item2">W??/a>)
消除警告: a)理解?然后b)更改你的代码L除警告ƈ让你惌它所做的事情对h和编译器都更清楚.
一定要做这一?即一开始程序看h正确q行?或者即使你肯定警告是良性的.即是良性警告也可以使后面的指出真正危险的警告变得隐?
例子
// 文g: myproj/my_lambda.h -- 包装Boost的lambda.hpp
// L使用q个文g,而不直接使用lambda.hpp.
// 注意: 我们的构建现在自动检? "grep lambda.hpp
// Boost.Lambda产生我们所知道的无害的~译警告.
// 当作者修正它时我们将U除下面?pragma语句,但是q个头文件仍存?
//
#pragma warning(push) // 仅屏蔽这个头文g
#pragma warning(disable:4512)
#pragma warning(disable:4180)
#include
// ?不用提C的用户自定义分配器内部 ?br>
// 警告: "unused parameter 'localityHint'"
pointer allocate( size_type numObjects, const void *localityHint = 0 ) {
return static_cast
}
// 新版? 消除警告
pointer allocate( size_type numObjects, const void * /* localityHint */ = 0 ) {
return static_cast
}// 警告: "变量'lock'定义了但却从未?"
void Fun() {
Lock lock;
// ?br>
}
// 新版? 消除了警?br>void Fun() {
Lock lock;
lock;
// ?br>
}
// 警告: 丢失"return"
int Fun( Color c ) {
switch( c ) {
case Red: return 2;
case Green: return 0;
case Blue:
case Black: return 1;
}
}
// 新版? 消除警告
int Fun( Color c ) {
switch( c ) {
case Red: return 2;
case Green: return 0;
case Blue:
case Black: return 1;
default: assert( !"should never get here!" ); // !"string"的gؓ(f)false
return -1;
}
}例外
有时~译器可能发Z个厌烦的甚至ƺ骗性的警告(比如Ua(b)的扰׃?,但没有可提供的方法去消除?而且M改代码去消除它可能是不可实现的或是徒劳的工作.在这些罕见的情况?作ؓ(f)一个团队决{?除去q个只是无聊的警告的烦h的工作是:仅特定警告无效,q尽可能是局部性的,q写一个清晰的注释文档说明Z么这样做是必要的.
参?/h3>
[Meyers97] $48 · [Stroustrup94] $2.6.2
2. 使用自动构徏pȝ
摘要
?单个)按钮:使用一个无需用户参与的全自动("一键触?)构徏pȝ.
讨论
一个一键触发式构徏Ҏ(gu)是基本的.它必进行可靠的和可重复的{?你的源文g转换为可交付的程序包.有很多自动构建工具可以?没有理由不去用它.挑选一?使用?
我们已见q一些忽视了"一键触?式要求的l织.一些h认ؓ(f)随处点几下鼠?可以运行一些工h注册COM/CORBA服务,或通过手工定制的一个合理构E拷贝一些文?但是你没有时间和_֊可以费在一些机器能做得更好更快的事情上.你需要一键触发式的自动化的和可靠的构?
成功的构建应该是没有M警告?见第1?.理想化的构徏不生扰׃?而仅是一个日志消?"构徏成功完成."
有两个构建模?增量构徏和完全构?增量构徏仅重上自增量构徏或完全构Z来被修改q的文g.推论:两个q箋的增量构Z的后者应该没有Q何输出文?如果有的?你可能有一个依赖环(见第22?,或者你的构建系l执行了不必要的操作(例如生成不合理的临时文g而只是丢弃它?.
一个工E可以有不同形式的完全构?考虑用一pd本质的特征确定你的构建的参数;很可能候选者就是目标式体系l构、调试和发布、或更广(基本文g和全部文件和完全安装).一个构|可以创Z个品的基本的可执行文g和库,另一个可能也创徏一些辅助文?一个完全充实的构徏也可能创Z个包含你所有文件、可重发布的W三方库和安装代码的安装E序.
随着工程的进?没有自动构徏的花费也在增?如果你一开始没有用,你将费很多旉和资?更糟p的?随着自动构徏成ؓ(f)无法抉|的需?你将?x)有比项目一开始更多的压力.
大项目可能有一?构徏?ȝ",他的工作是照料构徏pȝ.
参?/h3>
[Brooks95] $13, $19 · [Dewhurst03] $1 · [GnuMake] · [Stroustrup00] $9.1
3. 使用一个版本控制系l?/h2>
摘要
好记性比不上烂笔?使用一个版本控制系l?VCS).决不要让出的文g保留很长旉.一旦你的更新的单元通过试尽快检?保入的代码不会(x)破坏整个构徏.
讨论
几乎所有不q_的工E都需要一个以上的开发者和/或超q一周的工作?在这L(fng)工程?你将需要比较同一文g的历史版本以定变化是什么时??或被?引入?你也需要控制和理源代码的变化.
当有多个开发者时,几个开发者很可能?x)在同一旉对同一文g的不同部分进行ƈ行地更改.你需要工具以自动q行文g的检出和恢复,以及(qing)在某些时候对q发~辑的合q?VCS自动操作和控制检?恢复以及(qing)合ƈ.VCS比手工做的更快更准确.而且你不用花旉每天的去摆弄那些重复性的工作,你有软g要写.
不要破坏构徏.在VCS中的代码必须L可以成功构徏?
存在很多的版本控制系l可供选择,没有理由不去用它.最便宜和流行的是cvs(见参?.它是一个灵zȝ工具,兯TCP/IP讉KҎ(gu)?可选择性的提高安全?通过用安全外壳SSH作ؓ(f)后端),卓越的脚本管?甚至有图形接?许多其它VCS也将cvs作ؓ(f)标准L?或基于它构徏新的功能.
例外
从始至终只花一周左x间的一个程序员的项目或许可以不需要VCS而生存吧.
参?/h3>
[BetterSCM] · [Brooks95] $11, $13 · [CVS]
4. 在代码审阅上作投?/h2>
摘要
代码审阅:更多双眼睛将?x)带来更好的质?展示你的代码,qM人的.你们都将怺学习(fn)或受?
讨论
一个良好的代码审阅q程在许多方面都对你的团队有好处.它可?
即你的雇主q不支持代码审阅Ҏ(gu),你也要增加管理知?提示:要开?l他们看q本?以及(qing)无论如何要尽你最大努力去安排旉q引导审阅的q行.q时间是值得q.
代码审阅作Z的Y件开发周期的一常规程?如果你和你的队友赞同ZȀ?也可能是挫折)的奖惩制?׃(x)好得?
不要做得太Ş式化?写一简单的邮gp够将代码审阅做得很好?q会(x)使你更容易跟t自qq程以及(qing)避免重复.
当审阅他人的代码?你可能想在旁边保留一个供参考的清单.H以Z个好的清单可能正是你正在ȝq本书的目录?满意?
摘要:我们知道我们在给"p?布道,但是不得不说.你们的自负或自我M也许讨厌代码审阅,但你们中的少量天才程序员喜欢?因ؓ(f)它会(x)有成效ƈ使代码更?使程序更强健.
参?/h3>
[Constantine95] $10, $22, $33 · [McConnell93] $24 · [MozillaCRFAQ]
]]>
我想大家看看我的代码,l我一Ҏ(gu)见和.
]]>
在模板参C,cd参数可以q样构?
template_class< type( type1, type2, ... ) > a_class;
比如,可以void( void ), void(), void( int ), 也可以int( void ), string( int ){等,~译器是它们当作不同的cd的来处理?Ҏ(gu),我写了一些代码作了一下测?见文?.但我也仅仅是有一个感性的认识而已,对于其ؓ(f)什么可以这?因ؓ(f)从未见哪本书上介l过q样的用?,我一点也不知?
希望大家帮我释疑,也希望cpunion来帮我一?谢谢!
#include <iostream>
typedef void(*fun)(int);
using namespace std;
template< typename T >
struct Base
{
void test()
{
cout << "Base
cout << "Base<" << typeid(T).name() << ">" << endl;
}
};
template<>
struct Base < void >
{
void test()
{
cout << "Base
}
};
template<>
struct Base < void( int ) >
{
void test()
{
cout << "Base
}
};
template<>
struct Base < fun >
{
void test()
{
cout << "Base
}
};
template<>
struct Base < int( string, int, char ) >
{
void test()
{
cout << "Base
}
};
int main(int argc, char* argv[])
{
Base< void > b_void;
Base< void( int ) > b_void_int;
b_void.test();
b_void_int.test();
Base< int( string, int, char ) > b_int;
Base< fun > b_fun;
b_int.test();
b_fun.test();
Base< Base< void > ( Base < int ( string, int, char ) > ) > b_complex;
b_complex.test();
return 0;
}
]]>
以下是具体的描述:
namespace code
{
enum CodeType
{ UTF_8, UNICODE };
template< CodeType srcT, CodeType desT >
struct ConvertType
{};
template<>
struct ConvertType < UTF_8, UNICODE >
{
typedef char srcType;
typedef wchar_t desType;
};
template< CodeType srcT, CodeType desT >
struct Convert
{};
template<>
struct Convert< UTF_8, UNICODE >
{
//error C2899: 不能在模板声明之外用类型名U?/SPAN>
typedef typename ConvertType< UTF_8, UNICODE >::srcType srcType; //!
typedef typename ConvertType< UTF_8, UNICODE >::desType desType; //!
};
} //namespace code
/**//*
q里Ҏ(gu)不需要typename.
typename除用在模板声明中?只能用于说明模板cȝ成员是一个类?
例如:
template
// Another way
template
typedef double DoubleType;
typename X
};
而如果不是模板类,则不能用typename.q时,它ƈ不是多余?而是一定不能要?
例如:
template<> struct X< X
typename X
X
};
我前面的代码也是q样的情?ConvertType< UTF_8, UNICODE >已经是一个具体的cM,不要是模板类,所以ConvertType< UTF_8, UNICODE >::srcType前不能加typename.
]]>
但想了几天了,都没有一个合适的Ҏ(gu)来实?
?.....
今天先试着写了?找找感觉,接着再想?..