This document is a companion to theC++ Coding Standard. It collects various informalhints on aspects to consider when designing and implementing code in the FOO software stack.
Available C++11 features
In code compiled for all STB toolchains (i.e., most code), we have support forthe subset of C++11 features implemented by the oldest GCC version in ourtoolchains. The lower bar is currentlyGCC 4.4:
In code only compiled with newer toolchains, it is allowed to use newerfeatures, but please refrain from using newer features in code that in thefuture might be useful for toolchains with older GCC versions. One notable caseis unit tests where there are no restrictions since such code is built only bythe host compiler.
See also C++0x/C++11 Support in GCC.
C++11 hints
Here is a summary of things to consider when writing new code.
Watch out for user-defined literals
Before C++11:
printf("x is %"PRIu64", y is %"PRIu64"\n", x, y);
Now:
printf("x is %" PRIu64 ", y is %" PRIu64 "\n", x, y);
Spaces must be added around macros as shown above since the code otherwise willfail to compile. This is because the code is interpreted as referring to auser-defined literal.
No need to add space between “>
” characters in template argument lists
Before C++11:
std::map<int, std::vector<int> >
Now:
std::map<int, std::vector<int>>
auto
specifier
Before C++11:
TContainer::const_iterator iter = Container.find(x);
Now:
auto iter = Container.find(x);
See also auto specifier.
Scoped (strongly-typed) enum
Before C++11:
enum TStatus {
STATUS_READY,
STATUS_SET,
STATUS_GO
};
Now:
enum class TStatus {
READY,
SET,
GO
};
See also scopedenumerations.
Container literals (list initialization)
Before C++11:
std::vector<int> x;
x.push_back(1);
x.push_back(2);
x.push_back(3);
Now:
std::vector<int> x = {1, 2, 3};
// Or:
std::vector<int> x({1, 2, 3});
// Or:
std::vector<int> x{1, 2, 3};
Before C++11:
std::map<std::string, int> x;
x["a"] = 1;
x.insert(std::make_pair("b", 2));
x.insert(std::map<std::string, int>::value_type("c", 3));
Now:
std::map<std::string, int> x = {{"a", 1}, {"b", 2}, {"c", 3}};
// Or:
std::map<std::string, int> x({{"a", 1}, {"b", 2}, {"c", 3}});
// Or:
std::map<std::string, int> x{{"a", 1}, {"b", 2}, {"c", 3}};
See also listinitialization.
static_assert
Before C++11:
#include <boost/static_assert.hpp>
BOOST_STATIC_ASSERT(x);
Now:
static_assert(x, "message");
std::shared_ptr
andstd::weak_ptr
Before C++11:
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
boost::shared_ptr<TExample> s;
boost::weak_ptr<TExample> w;
Now:
#include <memory>
std::shared_ptr<TExample> s;
std::weak_ptr<TExample> w;
See alsostd::shared_ptr
andstd::weak_ptr
.
std::unique_ptr
Before C++11:
#include <boost/scoped_ptr.hpp>
boost::scoped_ptr<TExample> x;
Now:
#include <memory>
const std::unique_ptr<TExample> x; // If no call to the reset method is needed.
std::unique_ptr<TExample> x; // If a call to the reset method is needed.
Before C++11:
#include <memory>
std::auto_ptr<TExample> x;
Now:
#include <memory>
std::unique_ptr<TExample> x;
Note: Use std::move
tomove value out of an std::unique_ptr
.
See alsostd::unique_ptr
.
std::bind
,std::function
and std::ref
Before C++11:
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/ref.hpp>
typedef boost::function<void ()> TFunction;
boost::bind(&TClass::Method, boost::ref(x), _1);
Now:
#include <functional>
using std::placeholders::_1;
typedef std::function<void ()> TFunction;
std::bind(&TClass::Method, std::ref(x), _1);
See alsostd::bind
,std::function
andstd::ref
.
Logging
Log levels
Level | Explanation | Example |
---|---|---|
Fatal | A fatal error has occurred that can not be handled and prevents further execution. This log line should always be followed by a program termination – never use one without the other (tip: useKABORT ). Fatals should never be reached in production code and always indicate a bug somewhere in the system. | “Could not connect to name service”, “Caught an unknown exception” |
Error | An error has occurred that affects some core functionality but can be handled and does not prevent further execution. Errors may be the symptoms of bugs, but may also be the result of problems in the environment/configuration/input. | “VoD server not found”, “Child process exited unexpectedly” |
Warning | Something out of the ordinary has happened but does not have any direct impact on the current task. It may be caused by input that is missing or out of bounds. It can be the symptom of bugs in the calling code. | “Missing configuration, using default”, “Resource already open” |
Note | The code has reached a point where it is informative to put a message in the log. It could be triggered by a state change, an event or user input that provides useful information to a working system. | “HDMI connected”, “Entering standby” |
Debug | Used to provide information that can be used in debugging without requiring specific knowledge about the code internals. It could be minor state changes or extra information in addition to another log message. No pure development debugging messages should be enabled in production code. | “IP address renewed”, “Initialization done, entering event loop” |
How to log
All FOO code must, when possible, use theKDebug macros for logging:
KNOTE("log message");
Do not use TTracker
or fprintf(stderr, ...)
explicitly (unless necessary):
TTracker::GetProcessTracker()->Note("log message");
Tracker->Note("log message");
fprintf(stderr, "<N>log message\n");
Note: Producing output from commandline programs, e.g. toish
, is not“logging”.
Debug log messages
Log messages on the debug level (“debug log messages”) can be used duringdevelopment but should normally not exist in production code. This is to avoidspamming the log, since too much logging causes performance problems and canconceal other log messages that indicate a real problem. In short: only logreal problems or points of general interest in production code.
During development, it may be useful to have debug log messages to tracefunction entry/exit (tip: useKTRACE_FUNCTION
,variable values or other points of interest. Before the code is submitted tothe revision control system, debug log messages should be removed or protectedby a define (that is undefined by default). Alternatively, let the debug logmessages beenabled at runtime.Note that runtime-enabled debug log messages still have a performance penalty,so use them sparingly.
How to write good log messages
Some general tips on how to write good log messages:
- Be concise. Logs should be informative and easy to understand. Prefer short expressive statements to longer, grammatically flawless sentences. Avoid capital letters and special characters just to get attention.
- Avoid spamming. Do not repeat yourself unless there is something new to report. It is often worth a few extra lines of code to avoid log spamming. Think one extra time before adding log lines to heavily shared code.
- Use the correct levels. Understand what level is appropriate for each log line. Remember that the failure of some functionality may be the result of an explicit configuration and thus could be expected. Keep in mind that traces often are filtered out and no warnings/errors/fatals should be shown when the box operates as expected.