C++ Dos and Don'ts

不包含不用的头文件;
尽可能使用前向声明替代头文件包含;
将嵌套类实现放在实现代码中;
将静态实现细节尽可能放在实现代码中;
不要在头文件生命中inline代码;
不要inline构造析构函数;
不要inline虚函数;

原文如下,链接是:http://www.chromium.org/developers/coding-style/cpp-dos-and-donts

Minimize Code in Headers

Don't include headers you don't need. Especially in headers.

I've seen several places where a header will include something, like <deque> or  "googleurl/src/gurl.h" and then not use the std::deque or GURL in the  file. These are probably oversights from previous refactorings or  reorganizations where the files used to be necessary, but they should  be fixed whenever they are seen.

Forward declare classes instead of including headers.

You can use forward declarations in all the following cases:

class Forward;
class ObjectUser {
  public:
    ObjectUser(Forward by_value);
    void OrByPointer(Forward* by_pointer);
    void OrByReference(const Forward& by_reference);
    Forward OrReturnValue();

  private:
    Forward* pointer_member_;
    scoped_ptr<Forward> most_smart_pointer_templates_;
    std::vector<Forward> some_stl_containers_;
    std::map<std::string, Forward> values_in_maps_;
};

But you can't forward declare in other situations:

class WontCompile {
  private:
    // But you can't just:
    Forward cant_full_member_;
    std::deque<Forward> cant_some_other_stl_ containers_;
};

Whenever you can forward declare, you should forward declare instead of  including a header.

Move inner classes into the implementation.

You can also forward declare classes inside a class:

class Whatever {
  public:
    /* ... */
  private:
    struct DataStruct;
    std::vector<DataStruct> data_;
};

Any headers that DataStruct needed no longer need to be included in the header  file and only need to be included in the implementation. This will  often let you pull  headers includes out of the header. For reference, the syntax in the  implementation file is:

struct Whatever::DataStruct {
};

Note that sometimes you can't do this because a handful of STL data structures  require the full definition at declaration time (most notably, std::deque and  the STL adapters that wrap it).

Move static implementation details to the implementation whenever possible.

If you have the class in a header file:

#include "BigImplementationDetail.h"
class PublicInterface {
  public:
    /* ... */
  private:
    static BigImplementationDetail detail_;
};

You should try to move that from a class member into the anonymous namespace in  the implementation file:

namespace {
BigImplementationDetail detail_;
}  // namespace

That way, people who don't use your interface don't need to know about or care  about BigImplementationDetail.

You can do this for helper functions that have hard to forward declare types,  too.

Stop inlining code

BACKGROUND: We're doing too much inlining. Remember that definitions in classes  are requested to be inlined. Remember that asking the compiler to inline a  method is a suggestion, one that's often ignored by the compiler. A compiler  that never inlined anything would be perfectly standards compliant. Every file  that has to use an inline method will also emit a function version in the  resulting .o, even if the method was inlined. (This is to support function  pointer behaviour properly.)

class InlinedMethods {
  InlinedMethods() {
    // This constructor is equivalent to having the inline keyword in front
    // of it!
  }
  void Method() {
    // Same here!
  }
};

Stop inlining complex methods.

class DontDoThis {
  public:
    int ComputerSomehting() {
      int sum =0;
      for (int i = 0; i < shurg; ++i) {
        sum += OtherMethod(i, ... );
      }
      return sum;
    }
};

Anything more than a few operations on integral data types will probably not be  inlined by the compiler. Remember that inline is a suggestion, and that you're  just adding crud to the .o files which the linker will need to do work to  resolve.

If the method deals with implementation details, there's also a good chance that you could eliminate some included headers in the header.

Stop inlining constructors and destructors.

Constructors and destructors are often significantly more complex than you  think they are, especially if your class has any non-POD data members. Many STL  classes have inlined constructors/destructors which may be copied into your  function body. Because the bodies of these appear to be empty, they often seem  like trivial functions that can safely be inlined.  Don't give in to this  temptation.  Define them in the implementation file unless you really need  them to be inlined.  Even if they do nothing now, someone could later add  something seemingly-trivial to the class and make your hundreds of inlined  destructors much more complex.

For more information, read Item 30 in Effective C++.

Even worse though, inlining constructors/destructors prevents you from using
forward declared variables.

class Forward;
class WontCompile {
  public:
    // THIS WON'T COMPILE, BUT IT WOULD HAVE IF WE PUT THESE IN THE
    // IMPLEMENTATION FILE!
    //
    // The compiler needs the definition of Forward to call the
    // vector/scoped_ptr ctors/dtors.
    Example() { }
    ~Example() { }

  private:
    std::vector<Forward> examples_;
    scoped_ptr<Forward> super_example_;
};

When you CAN inline constructors and destructors.

The above case had two class members and that's a large part of the reason it's more complex than it seems. There are cases where it is better to have an inline constructor and  no destructor.

struct Data {
  Data() : count_one(0), count_two(0) {}

  int count_one;
  int count_two;
};

C++ has the concept of a  trivial destructor . In the above case, no destructor will be run because it only contains integral data types and the destructor is implicit. The constructor (since it has no base class and only integral data members) will be two trivial integer operations, which is OK to inline.

If you aren't sure, than you probably shouldn't try this.

You CAN inline virtual destructors in pure abstract base classes.

For example, you don't have to make a CC file for this:

class Interface {
  public:
   virtual ~Interface() {}
  
   virtual void DoSomething(int parameter) = 0;
   virtual int GetAValue() = 0;  
};

But note that it really needs to be an abstract base class. These two "interfaces" don't count:

class ClaimsToBeAnInterface : public base:RefCounted<ClaimsToBeAnInterface> {
 public:
  virtual ~ClaimsToBeAnInterface() { /* But derives from a template! */ }
};

class HasARealMember {
 public:
  virtual void InterfaceMethod() = 0;
  virtual ~HasARealMember() {}

 protected:
  vector<string> some_data_;
};

Think about your accessors.

Not all accessors are light weight. Compare:

class Foo {
 public:
   int count() const { return count_; }

 private:
  int count_;
};

Which is a simple compared to the simple looking:

struct MyData {
  vector<GURL> urls_;
  base::Time last_access_;
};

class Manager {
 public:
  MyData get_data() { return my_data_; }

 private:
  MyData my_data_;
};

This is complex because the underlying copy constructor calls are going to be complex. (Also, they're going to be synthesized, which is bad.)

Stop inlining virtual methods.

You can't inline virtual methods under most circumstances, even if the method  would otherwise be inlined because it's very short. The compiler must do  runtime dispatch on any virtual method where the compiler doesn't know the  object's complete type, which rules out the majority of cases where you have an  object.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值