logo

C++ - Versus

Last Updated: 2022-03-20

Declarations vs Definitions

  • Declaration: give it a name
  • Definition: give it a name and all the info the compiler needs to create the code for that name

In C++ there is an important distinction between a declaration (“There is a class called Foo”) and a definition (“here is class Foo including its members, methods, etc”). Since C++ attempts to be a language that can be compiled in a single pass, referring to an entity by name is an error if that entity hasn’t at least been declared at the point of that use. (Technically, a definition also counts as a declaration.)

// A forward declaration
class Foo;

struct vs class vs union

  • struct: data members default to public.
  • class: data members default to private.
  • union: a special class type that can hold only one of its non-static data members at a time. (Similar to oneof in ProtoConf)

Google style guide suggests: "Use a struct only for passive objects that carry data; everything else is a class."

https://google.github.io/styleguide/cppguide.html#Structs_vs._Classes

moveable vs copyable

A movable type = can be initialized and assigned from temporaries.

A copyable type = can be initialized or assigned from any other object of the same type.

Copy behavior is defined by the copy constructor and the copy-assignment operator. E.g.

Move behavior is defined by the move constructor and the move-assignment operator.

class Foo {
 public:
  Foo(const Foo& arg);             // copy constructor
  Foo(Foo&& arg);                  // move constructor
  Foo& operator=(const Foo& rhs);  // copy assignment operator
  Foo& operator=(Foo&& rhs);       // move assignment operator
  ...
};

A copyable example:

class Foo {
 public:
  Foo(const Foo& other) = default;
  Foo& operator=(const Foo& other) = default;
};

A move only example:

class Foo {
 public:

  // delete copy constructor and copy-assignment operator
  Foo(const Foo&) = delete;
  Foo& operator=(const Foo&) = delete;

  // default move constructor and move-assignment operator
  Foo(Foo&& other) = default;
  Foo& operator=(Foo&& other) = default;
};

A non-copyable and non-movable example:

class Foo {
 public:

  // delete copy constructor and copy-assignment operator
  Foo(const Foo&) = delete;
  Foo& operator=(const Foo&) = delete;

  // delete move constructor and move-assignment operator
  Foo(Foo&& other) = delete;
  Foo& operator=(Foo&& other) = delete;
};

Examples:

  • movable but not copyable: e.g. std::unique_ptr<int>
  • movable and copyable: int and std::string, for int, the move and copy operations are the same; for std::string, there exists a move operation that is less expensive than a copy.

Can be generated by the compiler, either implicitly or with = default.

enum vs enum class

You can define enums in 2 different ways: enum or enum class. Prefer enum class, since it create its own scope, and doesn't pollute the namespace that it is in. In comparison, an enum just spills its contents into the enclosing scope.