42
C++ Eleventy for ATS Style and Suggestions

Gude for C++11 in Apache Traffic Server

Embed Size (px)

Citation preview

Page 1: Gude for C++11 in Apache Traffic Server

C++ Eleventy for ATSStyle and Suggestions

Page 2: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 2

Introduction

C++11 (“eleventy”) is a major change in the language (Lisp rulz!) 7.0 release requires compilers that are C++11 compliant. Take advantage of new language features without going crazy.

You know who you are. Focus here is on ATS related features, not an overview of all changes.

Looking at just the features I think are the most useful for ATS coding.

Page 3: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 3

nullptr

A null pointer. Never worse and frequently better than

NULL 0

nullptr is of type nullptr_t - overloads are distinct from ‘0’ or NULL. Classes that involve pointers and numbers (e.g., strings) can now

differentiate ‘0’ as “zero” vs. “null”. This is required.

Do not use NULL. Should not use ‘0’ either to mean NULL.

Page 4: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 4

autoMake the compiler figure out the type

Useful to avoid having to write a type twice. auto thing = new Thing;

Types it would take days to figure out and don’t really matter. Iterators, complex containers, lambdas.

Local uses where the type is unimportant locally scoped variables.

{auto tmp = lhs;lhs = rhs;rhs = tmp;}

for loop variables (but see later section)

Page 5: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 5

auto

Qualifiers can be added to the computed type. const, volatile, lvalue reference, rvalue reference, pointer.

Requires an initialization expression from which to deduce the type.

Page 6: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 6

autoDon’t drive others crazy Easy to overuse.

Don’t make people guess about the type. Should be obvious or irrelevant.

Be extra careful with numerics. The compiler doesn’t always think it’s the same type you do. In many cases in ATS the numeric type needs to be very specific.

Page 7: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 7

Range-based for loops Iterate over elements in a container.

for (auto& item : acl_list) { item.update(); // …}

Container must support C++ standard iteration via begin / end methods begin / end functions An array with a declared length.

The variable for elements can be a value which will be a copy of the actual element.

The variable does not have to be declared auto but that’s easier.

Page 8: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 8

MethodoloyUseful advancements in method technology

Page 9: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 9

Delegating Constructors

init() methods are error prone and annoying. C++11 makes it possible to call a constructor from another constructor using

member initialization syntax.class Leif {

int a;

public:

Leif(int x) { if (0<x && x<=max) a=x; else throw bad_Leif(x); }

Leif() : Leif{42} { } Leif(string s) : Leif{lexical_cast<int>(s)} { }

// ...

};

Page 10: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 10

Prohibiting methods

Methods can be explicitly removed from the class.class X { X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete;}; Use this instead of declaring but not defining these methods. This works for any method including inherited methods.

Page 11: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 11

Defaulting methods

Methods can be defined as “default” which means use the compiler generated method.

Can only be used for methods that have compiler definitions. Theoretically not useful because doing nothing has the same effect.

Always use instead of defining a method that replicates default behavior. Make it explicit the default is being used.

Page 12: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 12

Member Initialization Class members can be initialized directly in the class declaration.

Overridden by constructor Avoid unobvious repetition in multiple constructors

Class Leif {Leif() : left(2), right(3), hair(HAT), phrase(“kill it with fire”), yet(4), another(5), member(7) {}

Leif(const char *text) : left(2), right(3), hair(HAT), phrase(text), yet(4), another(5), member(7) {}};// vs.class Leif {Leif() {}Leif(char const* text) : phrase(text) {}

int left = 2;int right = 3;HairStyle hair(HAT);// …};

Page 13: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 13

EThread::EThread() : generator((uint64_t)ink_get_hrtime_internal() ^ (uint64_t)(uintptr_t) this), ethreads_to_be_signalled(NULL), n_ethreads_to_be_signalled(0), main_accept_index(-1), id(NO_ETHREAD_ID), event_types(0), tt(REGULAR), current_metric(metrics + (ink_get_hrtime_internal() / HRTIME_SECOND) % N_EVENT_METRICS){ memset(thread_private, 0, PER_THREAD_DATA);}

EThread::EThread(ThreadType att, int anid) : generator((uint64_t)ink_get_hrtime_internal() ^ (uint64_t)(uintptr_t) this), ethreads_to_be_signalled(NULL), n_ethreads_to_be_signalled(0), main_accept_index(-1), id(anid), event_types(0), tt(att), server_session_pool(NULL), current_metric(metrics + (ink_get_hrtime_internal() / HRTIME_SECOND) % N_EVENT_METRICS){}

EThread::EThread(ThreadType att, Event *e) : generator((uint32_t)((uintptr_t)time(NULL) ^ (uintptr_t) this)), ethreads_to_be_signalled(NULL), n_ethreads_to_be_signalled(0), main_accept_index(-1), id(NO_ETHREAD_ID), event_types(0), tt(att), oneevent(e), current_metric(metrics + (ink_get_hrtime_internal() / HRTIME_SECOND) % N_EVENT_METRICS){ ink_assert(att == DEDICATED); memset(thread_private, 0, PER_THREAD_DATA);}

Page 14: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 14

class EThread : public Thread{ // ... The initialized members InkRand generator = static_cast<uint64_t>(Thread::get_hrtime_updated() ^ reinterpret_cast<uintptr_t>(this)); EThread **ethreads_to_be_signalled = nullptr; int n_ethreads_to_be_signalled = 0; unsigned int event_types = 0; Event *start_event = nullptr; ServerSessionPool *server_session_pool = nullptr;};

EThread::EThread() : id(NO_ETHREAD_ID), tt(REGULAR){ memset(thread_private, 0, P ER_THREAD_DATA);}EThread::EThread(ThreadType att, int anid) : id(anid), tt(att), server_session_pool(nullptr){ // …}EThread::EThread(ThreadType att, Event *e) : id(NO_ETHREAD_ID), tt(att), start_event(e){ memset(thread_private, 0, PER_THREAD_DATA);}

Page 15: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 15

override

Marks a method as overriding a super class method. No code effect. Useful to be sure the method really does override. Recommended.

Page 16: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 16

Explicit conversion operators

User type conversions can be marked explicit. This allows direct conversions but not implicit conversions. Classic example – conversion to bool.

In C++98 this also allows further conversion to pointer or numeric types. Worked around by making the conversion to a pointer to method. In C++11 mark conversion explicit.

Page 17: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 17

More stuff

Page 18: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 18

std::unique_ptr<T>#include <memory> Dynamically allocated object that is not shared. Default constructed to contain nullptr. When the instance is destroyed or has another value assigned it is

cleaned up. Clean up mechanism can be changed, defaults to the destructor for T. ats_scoped_XXX is modeled on this class.

Change should be easy for this reason. Always intended as a temporary measure until we could use C++ eleventy.

Page 19: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 19

std::unique_ptr<T>

Useful for Class members that cannot be statically declared but share the lifetime of

the class. Local temporary heap storage.

Page 20: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 20

Lambda

Lambda is a notation that creates an anonymous functor class and instantiates it. [] () mutable throw() -> T { /* … */ }

capture parameters optional optional return type code Common functionality in ECMA style languages (Perl, Python, JavaScript, …) Lambdas can be used as temporaries or stored

Via auto or std::function. It’s C++, both the lambda and its container are strongly typed.

Lambdas can bind objects in current scope either by value or reference. Be careful of variable lifetime vs. lambda lifetime. Value binding vs. mutable – by default values are const.

Page 21: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 21

Lambda Capture

Capture syntax basic “[=]” -> capture by value. “[&]” -> capture by reference. These capture any name used in that lambda that is not in the lambda

scope but in the enclosing scope. Capture syntax by name

“[=name]” -> capture “name” by value. “[&, =thing1, =thing2]” -> capture all names in use by reference except

“thing1” and “thing2” which are captured by value.

Page 22: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 22

Lambda curry

Lambdas can be used to curry and bind functions. Create shims between the function you have and what the API needs.

Change the set of parameters or fix parameters to specific values. Create a function object from an object instance and a method. Make Standard Template Library algorithms much more useful.

Page 23: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 23

Example

typedef std::function<void (const char*)> CallBack;void SetCallback(CallBack cb);

int some_function(const unsigned char* input) { … }

// … some other code site, convert some_function to expected callback form SetCallBack(lambda [] (const char* s) -> void { (void) some_function(reinterpret_cast<const unsigned char*>(s); }

Page 24: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 24

std::function#include <functional> Holds an object that can be called as a function.

Function, functor, lambda. Defined with a specific signature. Simplifies providing flexibility to caller. Good for global or process start callbacks. Can be used with lambdas to curry functions or pass method

callbacks. NOTE: This stores the function pointer only. If bound to a method it

does not preserve the object. May require allocation if passed a functor or lambda.

Page 25: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 25

constexpr

Marks a variable, method, or function as compile time computable. For variables, used in place of const. Static methods work as functions. Dynamic methods work if class instance used is constexpr.

Opposite of taint, “pure”. If all inputs are constexpr then result is constexpr. If any input is tainted (not constexpr) neither is result.

Can be used in non-compile time constant context. Purpose – do more general and complex compile time computations.

Page 26: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 26

constexpr

Consider a simple computation like# define BUFFER_SIZE_FOR_INDEX(i) (DEFAULT_BUFFER_BASE_SIZE * (1 << (i))) This is reduced to a constant during compilation. If an inline function

were usedinline size_t BUFFER_SIZE_FOR_INDEX(int i) { return DEFAULT_BUFFER_BASE_SIZE * (1<< i));} This would be cleaner but no longer always a constant. constexpr

makes it possible to have the best of defines and inline functions.inline constexpr size_t BUFFER_SIZE_FOR_INDEX(int i) { … }

Page 27: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 27

static_assert

Compile time assertion. Two arguments, a constexpr and a string. If the expression is not true, the compilation fails and the string is

printed. Equivalent used many places in ATS, either done dynamically or via

singleton constructor. Can use type information unlike #if.static_assert(INK_START_ERRNO > SOCK_ERROR, “Internal errono values overlap system errno values”);

Page 28: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 28

Rvalue reference

New qualifier – rvalue reference. “int&& rvr = 4;” lvalue vs. rvalue

lvalue has a name / specified by programmer. rvalue has no name / created by compiler (“temporary”).

“Universal reference” “&&” can mean either lvalue or rvalue reference if the type it qualifies is

deduced by compiler. Syntactic sugar only – all actual instantiations are lvalue or rvalue

reference.

Page 29: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 29

Perfect Forwarding

Addition of rvalue and “universal” references allows a function F to forward its arguments exactly to another function. Root cause – temporaries vs. variables. Previously this took 2N template implementations for an N parameter

function. Technically possible but rarely, if ever, done in practice.

The key trick is a “universal reference” can evolve in to an lvalue or rvalue reference as needed to forward the argument.

This is an obscure technique – if it’s not clear, don’t try to use it.

Page 30: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 30

Move

“Move semantics” is a combination of Bitwise copy Destructor skipping Object A is bitwise copied to object B without the destructor or constructor

of A or B invoked. Useful in specific situations where the contents of A are important

but neither A itself nor the contents of B are. But those situations show up very frequently.

B is a default constructed container element. B is a return value. B is raw memory that has never been constructed.

Page 31: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 31

std::move

Template formalization to provide additional control of movement. Specialize if needed for specific types.

When used it should be expected to result in the destruction of the object.

In many ways like auto_ptr but not done stupid.

// Fast container add that avoids a copyThing q;Container c;c.emplace(std::move(q));// assume q is invalid at this point.

Page 32: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 32

Enum class, storage

Enumerations can be classes. Creates type difference from numeric types. Constrains name space injection. Good for global / file scope enums.

Class nested enums should be plain. Enums can specific storage class.

Optimize memory footprint. Allow forward declaration / in name only.

Page 33: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 33

Uniform initialization

Bit of a misnomer but allows a wide variety of initializations with the same syntax. Aggregate initialization. Constructor invocation.

Uniform initialization can never be mistaken for a function definition. POD without a constructor is considered an aggregate.

For PODs with few members very handy. Pass temporary without writing a trivial constructor.

Notation is recursive.

Page 34: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 34

Uniform initialization

Can be overridden with constructor. Single argument of type std::initializer_list<T>. Note the list must be homogenous.

Can be used in container loops.for ( auto item const& : { “one”, “two”, “three” } ) { … }

This can avoid having to declare an array used in only one loop.

Page 35: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 35

Uniform initialization examples

struct Leif {int q;const char* phrase;};

void f(){ Leif l = Leif{1, “ack”}; Leif l{1, “ack”}; Leif clones[4] = { {1, “ack”}, {2, “make it so”},{3, “pebkac”},{4, “use lua!”}};}

Page 36: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 36

Uniform Initialization – another examplestruct Exile { bool deposed_p, const char* name, const char* reason; };

void make_soylent_green(Exile&& victim);

make_soylent_green(Exile { true, “Leif”, “too much hat wearing” });// or evenmake_soylent_green({ true, “Leif”, “too much hat wearing”});

Page 37: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 37

Raw Strings

Raw string literals allow alternate string delimiters to simplify escaping.

auto str = R”(a\\ literal “with” quotes (and parens))” Base syntax is a literal ‘R’ followed by a double quote then a

parenthese. String is terminated with parenthese and a double quote. Extra delimiter characters can be put between the “ and (.

The string is then terminated only with the same character sequence.auto str = R”ats(an “ats” quoted string with one \)ats”;

‘R’ can be prefixed with “u8”, “u”, “U”, or “L” for different encodings.

Page 38: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 38

std::array<T, N>

Equivalent to C array. Fixed size. Single chunk of memory. N must be a positive integral value.

Makes an array easier to use with other C++ features E.g. range for loops.

Page 39: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 39

Old Stuff

Page 40: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 40

Casting

Not new to C++11 but time to switch to actual C++ style Don’t use C style casts.

C style cast can do different things depending on the mood of the compiler. C++ casts make it clear what is being done.

static_cast dynamic_cast const_cast reinterpret_cast

Yes, it can look ugly. But it’s good for you.

Page 41: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 41

Anonymous namespace

Use of static to prevent external linkage is deprecated. Use the anonymous namespace instead.namespace { const char PLUGIN_NAME[] = “sorberizer”;}

Page 42: Gude for C++11 in Apache Traffic Server

Apache Traffic Server Summit Fall 2016 42

Inline functions

Inline functions are almost always a better choice than #define. Argument type checking. No order of evaluation or multiple evaluation issues. Control of namespace collisions

Even better with constexpr to get compile time constant folding.