Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Modern C++ Programming Cookbook
Modern C++ Programming Cookbook

Modern C++ Programming Cookbook: Recipes to explore data structure, multithreading, and networking in C++17

eBook
$38.99 $43.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Modern C++ Programming Cookbook

Learning Modern Core Language Features

The recipes included in this chapter are as follows:

  • Using auto whenever possible
  • Creating type aliases and alias templates
  • Understanding uniform initialization
  • Understanding the various forms of non-static member initialization
  • Controlling and querying object alignment
  • Using scoped enumerations
  • Using override and final for virtual methods
  • Using range-based for loops to iterate on a range
  • Enabling range-based for loops for custom types
  • Using explicit constructors and conversion operators to avoid implicit conversion
  • Using unnamed namespaces instead of static globals
  • Using inline namespaces for symbol versioning
  • Using structured bindings to handle multi-return values

Introduction

The C++ language has gone through a major transformation in the past decade with the development and release of C++11 and then later with its newer versions C++14 and C++17. These new standards have introduced new concepts, simplified or extended existing syntax and semantics, and overall transformed the way we write code. C++11 looks like a new language, and code written using the new standards is called modern C++ code.

Using auto whenever possible

Automatic type deduction is one of the most important and widely used features in modern C++. The new C++ standards have made it possible to use auto as a placeholder for types in various contexts and let the compiler deduce the actual type. In C++11, auto can be used for declaring local variables and for the return type of a function with a trailing return type. In C++14, auto can be used for the return type of a function without specifying a trailing type and for parameter declarations in lambda expressions. Future standard versions are likely to expand the use of auto to even more cases. The use of auto in these contexts has several important benefits. Developers should be aware of them, and prefer auto whenever possible. An actual term was coined for this by Andrei Alexandrescu and promoted by Herb Sutter--almost always auto (AAA).

How to do it...

Consider using auto as a placeholder for the actual type in the following situations:

  • To declare local variables with the form auto name = expression when you do not want to commit to a specific type:
        auto i = 42;          // int 
auto d = 42.5; // double
auto s = "text"; // char const *
auto v = { 1, 2, 3 }; // std::initializer_list<int>
  • To declare local variables with the auto name = type-id { expression } form when you need to commit to a specific type:
        auto b  = new char[10]{ 0 };            // char* 
auto s1 = std::string {"text"}; // std::string
auto v1 = std::vector<int> { 1, 2, 3 }; // std::vector<int>
auto p = std::make_shared<int>(42); // std::shared_ptr<int>
  • To declare named lambda functions, with the form auto name = lambda-expression, unless the lambda needs to be passed or return to a function:
        auto upper = [](char const c) {return toupper(c); };
  • To declare lambda parameters and return values:
        auto add = [](auto const a, auto const b) {return a + b;};
  • To declare function return type when you don't want to commit to a specific type:
        template <typename F, typename T> 
auto apply(F&& f, T value)
{
return f(value);
}

How it works...

The auto specifier is basically a placeholder for an actual type. When using auto, the compiler deduces the actual type from the following instances:

  • From the type of the expression used to initialize a variable, when auto is used to declare variables.
  • From the trailing return type or the type of the return expression of a function, when auto is used as a placeholder for the return type of a function.

In some cases, it is necessary to commit to a specific type. For instance, in the preceding example, the compiler deduces the type of s to be char const *. If the intention was to have a std::string, then the type must be specified explicitly. Similarly, the type of v was deduced as std::initializer_list<int>. However, the intention could be to have a std::vector<int>. In such cases, the type must be specified explicitly on the right side of the assignment.

There are some important benefits of using the auto specifier instead of actual types; the following is a list of, perhaps, the most important ones:

  • It is not possible to leave a variable uninitialized. This is a common mistake that developers do when declaring variables specifying the actual type, but it is not possible with auto that requires an initialization of the variable in order to deduce the type.
  • Using auto ensures that you always use the correct type and that implicit conversion will not occur. Consider the following example where we retrieve the size of a vector to a local variable. In the first case, the type of the variable is int, though the size() method returns size_t. That means an implicit conversion from size_t to int will occur. However, using auto for the type will deduce the correct type, that is, size_t:
        auto v = std::vector<int>{ 1, 2, 3 }; 
int size1 = v.size();
// implicit conversion, possible loss of data
auto size2 = v.size();
auto size3 = int{ v.size() }; // error, narrowing conversion
  • Using auto promotes good object-oriented practices, such as preferring interfaces over implementations. The lesser the number of types specified the more generic the code is and more open to future changes, which is a fundamental principle of object-oriented programming.
  • It means less typing and less concern for actual types that we don't care about anyways. It is very often that even though we explicitly specify the type, we don't actually care about it. A very common case is with iterators, but one can think of many more. When you want to iterate over a range, you don't care about the actual type of the iterator. You are only interested in the iterator itself; so, using auto saves time used for typing possibly long names and helps you focus on actual code and not type names. In the following example, in the first for loop, we explicitly use the type of the iterator. It is a lot of text to type, the long statements can actually make the code less readable, and you also need to know the type name that you actually don't care about. The second loop with the auto specifier looks simpler and saves you from typing and caring about actual types.
        std::map<int, std::string> m; 
for (std::map<int,std::string>::const_iterator it = m.cbegin();
it != m.cend(); ++it)
{ /*...*/ }

for (auto it = m.cbegin(); it != m.cend(); ++it)
{ /*...*/ }
  • Declaring variables with auto provides a consistent coding style with the type always in the right-hand side. If you allocate objects dynamically, you need to write the type both on the left and right side of the assignment, for example, int p = new int(42). With auto, the type is specified only once on the right side.

However, there are some gotchas when using auto:

  • The auto specifier is only a placeholder for the type, not for the const/volatile and references specifiers. If you need a const/volatile and/or reference type, then you need to specify them explicitly. In the following example, foo.get() returns a reference to int; when variable x is initialized from the return value, the type deduced by the compiler is int, and not int&. Therefore, any change to x will not propagate to foo.x_. In order to do so, one should use auto&:
        class foo { 
int x_;
public:
foo(int const x = 0) :x_{ x } {}
int& get() { return x_; }
};

foo f(42);
auto x = f.get();
x = 100;
std::cout << f.get() << std::endl; // prints 42
  • It is not possible to use auto for types that are not moveable:
        auto ai = std::atomic<int>(42); // error
  • It is not possible to use auto for multi-word types, such as long long, long double, or struct foo. However, in the first case, the possible workarounds are to use literals or type aliases; as for the second, using struct/class in that form is only supported in C++ for C compatibility and should be avoided anyways:
        auto l1 = long long{ 42 }; // error 
auto l2 = llong{ 42 }; // OK
auto l3 = 42LL; // OK
  • If you use the auto specifier but still need to know the type, you can do so in any IDE by putting the cursor over a variable, for instance. If you leave the IDE, however, that is not possible anymore, and the only way to know the actual type is to deduce it yourself from the initialization expression, which could probably mean searching through the code for function return types.

The auto can be used to specify the return type from a function. In C++11, this requires a trailing return type in the function declaration. In C++14, this has been relaxed, and the type of the return value is deduced by the compiler from the return expression. If there are multiple return values they should have the same type:

    // C++11 
auto func1(int const i) -> int
{ return 2*i; }

// C++14
auto func2(int const i)
{ return 2*i; }

As mentioned earlier, auto does not retain const/volatile and reference qualifiers. This leads to problems with auto as a placeholder for the return type from a function. To explain this, let us consider the preceding example with foo.get(). This time we have a wrapper function called proxy_get() that takes a reference to a foo, calls get(), and returns the value returned by get(), which is an int&. However, the compiler will deduce the return type of proxy_get() as being int, not int&. Trying to assign that value to an int& fails with an error:

    class foo 
{
int x_;
public:
foo(int const x = 0) :x_{ x } {}
int& get() { return x_; }
};

auto proxy_get(foo& f) { return f.get(); }

auto f = foo{ 42 };
auto& x = proxy_get(f); // cannot convert from 'int' to 'int &'

To fix this, we need to actually return auto&. However, this is a problem with templates and perfect forwarding the return type without knowing whether that is a value or a reference. The solution to this problem in C++14 is decltype(auto) that will correctly deduce the type:

    decltype(auto) proxy_get(foo& f) { return f.get(); } 
auto f = foo{ 42 };
decltype(auto) x = proxy_get(f);

The last important case where auto can be used is with lambdas. As of C++14, both lambda return type and lambda parameter types can be auto. Such a lambda is called a generic lambda because the closure type defined by the lambda has a templated call operator. The following shows a generic lambda that takes two auto parameters and returns the result of applying operator+ on the actual types:

    auto ladd = [] (auto const a, auto const b) { return a + b; }; 
struct
{
template<typename T, typename U>
auto operator () (T const a, U const b) const { return a+b; }
} L;

This lambda can be used to add anything for which the operator+ is defined. In the following example, we use the lambda to add two integers and to concatenate to std::string objects (using the C++14 user-defined literal operator ""s):

    auto i = ladd(40, 2);            // 42 
auto s = ladd("forty"s, "two"s); // "fortytwo"s

See also

  • Creating type aliases and alias templates
  • Understanding uniform initialization

Creating type aliases and alias templates

In C++, it is possible to create synonyms that can be used instead of a type name. This is achieved by creating a typedef declaration. This is useful in several cases, such as creating shorter or more meaningful names for a type or names for function pointers. However, typedef declarations cannot be used with templates to create template type aliases. An std::vector<T>, for instance, is not a type (std::vector<int> is a type), but a sort of family of all types that can be created when the type placeholder T is replaced with an actual type.

In C++11, a type alias is a name for another already declared type, and an alias template is a name for another already declared template. Both of these types of aliases are introduced with a new using syntax.

How to do it...

  • Create type aliases with the form using identifier = type-id as in the following examples:
        using byte    = unsigned char; 
using pbyte = unsigned char *;
using array_t = int[10];
using fn = void(byte, double);

void func(byte b, double d) { /*...*/ }

byte b {42};
pbyte pb = new byte[10] {0};
array_t a{0,1,2,3,4,5,6,7,8,9};
fn* f = func;
  • Create alias templates with the form template<template-params-list> identifier = type-id as in the following examples:
        template <class T> 
class custom_allocator { /* ... */};

template <typename T>
using vec_t = std::vector<T, custom_allocator<T>>;

vec_t<int> vi;
vec_t<std::string> vs;

For consistency and readability, you should do the following:

  • Not mix typedef and using declarations for creating aliases.
  • Use the using syntax to create names of function pointer types.

How it works...

A typedef declaration introduces a synonym (or an alias in other words) for a type. It does not introduce another type (like a class, struct, union, or enum declaration). Type names introduced with a typedef declaration follow the same hiding rules as identifier names. They can also be redeclared, but only to refer to the same type (therefore, you can have valid multiple typedef declarations that introduce the same type name synonym in a translation unit as long as it is a synonym for the same type). The following are typical examples of typedef declarations:

    typedef unsigned char   byte; 
typedef unsigned char * pbyte;
typedef int array_t[10];
typedef void(*fn)(byte, double);

template<typename T>
class foo {
typedef T value_type;
};

typedef std::vector<int> vint_t;

A type alias declaration is equivalent to a typedef declaration. It can appear in a block scope, class scope, or namespace scope. According to C++11 paragraph 7.1.3.2:

A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef specifier. In particular, it does not define a new type and it shall not appear in the type-id.

An alias-declaration is, however, more readable and more clear about the actual type that is aliased when it comes to creating aliases for array types and function pointer types. In the examples from the How to do it... section, it is easily understandable that array_t is a name for the type array of 10 integers, and fn is a name for a function type that takes two parameters of type byte and double and returns void. That is also consistent with the syntax for declaring std::function objects (for example, std::function<void(byte, double)> f).

The driving purpose of the new syntax is to define alias templates. These are templates which, when specialized, are equivalent to the result of substituting the template arguments of the alias template for the template parameters in the type-id.

It is important to take note of the following things:

  • Alias templates cannot be partially or explicitly specialized.
  • Alias templates are never deduced by template argument deduction when deducing a template parameter.
  • The type produced when specializing an alias template is not allowed to directly or indirectly make use of its own type.

Understanding uniform initialization

Brace-initialization is a uniform method for initializing data in C++11. For this reason, it is also called uniform initialization. It is arguably one of the most important features from C++11 that developers should understand and use. It removes previous distinctions between initializing fundamental types, aggregate and non-aggregate types, and arrays and standard containers.

Getting ready

For continuing with this recipe, you need to be familiar with direct initialization that initializes an object from an explicit set of constructor arguments and copy initialization that initializes an object from another object. The following is a simple example of both types of initialization, but for further details, you should see additional resources:

    std::string s1("test");   // direct initialization 
std::string s2 = "test"; // copy initialization

How to do it...

To uniformly initialize objects regardless of their type, use the brace-initialization form {} that can be used for both direct initialization and copy initialization. When used with brace initialization, these are called direct list and copy list initialization.

    T object {other};   // direct list initialization 
T object = {other}; // copy list initialization

Examples of uniform initialization are as follows:

  • Standard containers:
        std::vector<int> v { 1, 2, 3 };
std::map<int, std::string> m { {1, "one"}, { 2, "two" }};
  • Dynamically allocated arrays:
        int* arr2 = new int[3]{ 1, 2, 3 };    
  • Arrays:
        int arr1[3] { 1, 2, 3 }; 
  • Built-in types:
        int i { 42 };
double d { 1.2 };
  • User-defined types:
        class foo
{
int a_;
double b_;
public:
foo():a_(0), b_(0) {}
foo(int a, double b = 0.0):a_(a), b_(b) {}
};

foo f1{};
foo f2{ 42, 1.2 };
foo f3{ 42 };
  • User-defined POD types:
        struct bar { int a_; double b_;};
bar b{ 42, 1.2 };

How it works...

Before C++11 objects required different types of initialization based on their type:

  • Fundamental types could be initialized using assignment:
        int a = 42; 
double b = 1.2;
  • Class objects could also be initialized using assignment from a single value if they had a conversion constructor (prior to C++11, a constructor with a single parameter was called a conversion constructor):
        class foo 
{
int a_;
public:
foo(int a):a_(a) {}
};
foo f1 = 42;
  • Non-aggregate classes could be initialized with parentheses (the functional form) when arguments were provided and only without any parentheses when default initialization was performed (call to the default constructor). In the next example, foo is the structure defined in the How to do it... section:
        foo f1;           // default initialization 
foo f2(42, 1.2);
foo f3(42);
foo f4(); // function declaration
  • Aggregate and POD types could be initialized with brace-initialization. In the next example, bar is the structure defined in the How to do it... section:
        bar b = {42, 1.2}; 
int a[] = {1, 2, 3, 4, 5};

Apart from the different methods of initializing the data, there are also some limitations. For instance, the only way to initialize a standard container was to first declare an object and then insert elements into it; vector was an exception because it is possible to assign values from an array that can be prior initialized using aggregate initialization. On the other hand, however, dynamically allocated aggregates could not be initialized directly.

All the examples in the How to do it... section use direct initialization, but copy initialization is also possible with brace-initialization. The two forms, direct and copy initialization, may be equivalent in most cases, but copy initialization is less permissive because it does not consider explicit constructors in its implicit conversion sequence that must produce an object directly from the initializer, whereas direct initialization expects an implicit conversion from the initializer to an argument of the constructor. Dynamically allocated arrays can only be initialized using direct initialization.

Of the classes shown in the preceding examples, foo is the one class that has both a default constructor and a constructor with parameters. To use the default constructor to perform default initialization, we need to use empty braces, that is, {}. To use the constructor with parameters, we need to provide the values for all the arguments in braces {}. Unlike non-aggregate types where default initialization means invoking the default constructor, for aggregate types, default initialization means initializing with zeros.

Initialization of standard containers, such as the vector and the map also shown above, is possible because all standard containers have an additional constructor in C++11 that takes an argument of type std::initializer_list<T>. This is basically a lightweight proxy over an array of elements of type T const. These constructors then initialize the internal data from the values in the initializer list.

The way the initialization using std::initializer_list works is the following:

  • The compiler resolves the types of the elements in the initialization list (all elements must have the same type).
  • The compiler creates an array with the elements in the initializer list.
  • The compiler creates an std::initializer_list<T> object to wrap the previously created array.
  • The std::initializer_list<T> object is passed as an argument to the constructor.

An initializer list always takes precedence over other constructors where brace-initialization is used. If such a constructor exists for a class, it will be called when brace-initialization is performed:

    class foo 
{
int a_;
int b_;
public:
foo() :a_(0), b_(0) {}

foo(int a, int b = 0) :a_(a), b_(b) {}
foo(std::initializer_list<int> l) {}
};

foo f{ 1, 2 }; // calls constructor with initializer_list<int>

The precedence rule applies to any function, not just constructors. In the following example, two overloads of the same function exist. Calling the function with an initializer list resolves to a call to the overload with an std::initializer_list:

    void func(int const a, int const b, int const c) 
{
std::cout << a << b << c << std::endl;
}

void func(std::initializer_list<int> const l)
{
for (auto const & e : l)
std::cout << e << std::endl;
}

func({ 1,2,3 }); // calls second overload

This, however, has the potential of leading to bugs. Let's take, for example, the vector type. Among the constructors of the vector, there is one that has a single argument representing the initial number of elements to be allocated and another one that has an std::initializer_list as an argument. If the intention is to create a vector with a preallocated size, using the brace-initialization will not work, as the constructor with the std::initializer_list will be the best overload to be called:

    std::vector<int> v {5};

The preceding code does not create a vector with five elements, but a vector with one element with a value 5. To be able to actually create a vector with five elements, initialization with the parentheses form must be used:

    std::vector<int> v (5);

Another thing to note is that brace-initialization does not allow narrowing conversion. According to the C++ standard (refer to paragraph 8.5.4 of the standard), a narrowing conversion is an implicit conversion:

- From a floating-point type to an integer type
- From long double to double or float, or from double to float, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly)
- From an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted to its original type
- From an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted to its original type.

The following declarations trigger compiler errors because they require a narrowing conversion:

    int i{ 1.2 };           // error 

double d = 47 / 13;
float f1{ d }; // error
float f2{47/13}; // OK

To fix the error, an explicit conversion must be done:

    int i{ static_cast<int>(1.2) }; 

double d = 47 / 13;
float f1{ static_cast<float>(d) };
A brace-initialization list is not an expression and does not have a type. Therefore, decltype cannot be used on a brace-init list, and template type deduction cannot deduce the type that matches a brace-init list.

There's more

The following sample shows several examples of direct-list-initialization and copy-list-initialization. In C++11, the deduced type of all these expressions is std::initializer_list<int>.

auto a = {42};   // std::initializer_list<int>
auto b {42}; // std::initializer_list<int>
auto c = {4, 2}; // std::initializer_list<int>
auto d {4, 2}; // std::initializer_list<int>

C++17 has changed the rules for list initialization, differentiating between the direct- and copy-list-initialization. The new rules for type deduction are as follows:

  • for copy list initialization auto deduction will deduce a std::initializer_list<T> if all elements in the list have the same type, or be ill-formed.
  • for direct list initialization auto deduction will deduce a T if the list has a single element, or be ill-formed if there is more than one element.

Base on the new rules, the previous examples would change as follows: a and c are deduced as std::initializer_list<int>; b is deduced as an int; d, which uses direct initialization and has more than one value in the brace-init-list, triggers a compiler error.

auto a = {42};   // std::initializer_list<int>
auto b {42}; // int
auto c = {4, 2}; // std::initializer_list<int>
auto d {4, 2}; // error, too many

See also

  • Using auto whenever possible
  • Understanding the various forms of non-static member initialization

Understanding the various forms of non-static member initialization

Constructors are a place where non-static class member initialization is done. Many developers prefer assignments in the constructor body. Aside from the several exceptional cases when that is actually necessary, initialization of non-static members should be done in the constructor's initializer list or, as of C++11, using default member initialization when they are declared in the class. Prior to C++11, constants and non-constant non-static data members of a class had to be initialized in the constructor. Initialization on declaration in a class was only possible for static constants. As we will see further, this limitation was removed in C++11 that allows initialization of non-statics in the class declaration. This initialization is called default member initialization and is explained in the next sections.

This recipe will explore the ways the non-static member initialization should be done.

How to do it...

To initialize non-static members of a class you should:

  • Use default member initialization for providing default values for members of classes with multiple constructors that would use a common initializer for those members (see [3] and [4] in the following code).
  • Use default member initialization for constants, both static and non-static (see [1] and [2] in the following code).
  • Use the constructor initializer list to initialize members that don't have default values, but depend on constructor parameters (see [5] and [6] in the following code).
  • Use assignment in constructors when the other options are not possible (examples include initializing data members with pointer this, checking constructor parameter values, and throwing exceptions prior to initializing members with those values or self-references of two non-static data members).

The following example shows these forms of initialization:

    struct Control 
{
const int DefaultHeigh = 14; // [1]
const int DefaultWidth = 80; // [2]

TextVAligment valign = TextVAligment::Middle; // [3]
TextHAligment halign = TextHAligment::Left; // [4]

std::string text;

Control(std::string const & t) : text(t) // [5]
{}

Control(std::string const & t,
TextVerticalAligment const va,
TextHorizontalAligment const ha):
text(t), valign(va), halign(ha) // [6]
{}
};

How it works...

Non-static data members are supposed to be initialized in the constructor's initializer list as shown in the following example:

    struct Point 
{
double X, Y;
Point(double const x = 0.0, double const y = 0.0) : X(x), Y(y) {}
};

Many developers, however, do not use the initializer list, but prefer assignments in the constructor's body, or even mix assignments and the initializer list. That could be for several reasons--for larger classes with many members, the constructor assignments may look easier to read than long initializer lists, perhaps split on many lines, or it could be because they are familiar with other programming languages that don't have an initializer list or because, unfortunately, for various reasons they don't even know about it.

It is important to note that the order in which non-static data members are initialized is the order in which they were declared in the class definition, and not the order of their initialization in a constructor initializer list. On the other hand, the order in which non-static data members are destroyed is the reversed order of construction.

Using assignments in the constructor is not efficient, as this can create temporary objects that are later discarded. If not initialized in the initializer list, non-static members are initialized via their default constructor and then, when assigned a value in the constructor's body, the assignment operator is invoked. This can lead to inefficient work if the default constructor allocates a resource (such as memory or a file) and that has to be deallocated and reallocated in the assignment operator:

    struct foo 
{
foo()
{ std::cout << "default constructor" << std::endl; }
foo(std::string const & text)
{ std::cout << "constructor '" << text << "'" << std::endl; }
foo(foo const & other)
{ std::cout << "copy constructor" << std::endl; }
foo(foo&& other)
{ std::cout << "move constructor" << std::endl; };
foo& operator=(foo const & other)
{ std::cout << "assignment" << std::endl; return *this; }
foo& operator=(foo&& other)
{ std::cout << "move assignment" << std::endl; return *this;}
~foo()
{ std::cout << "destructor" << std::endl; }
};

struct bar
{
foo f;

bar(foo const & value)
{
f = value;
}
};

foo f;
bar b(f);

The preceding code produces the following output showing how data member f is first default initialized and then assigned a new value:

default constructor 
default constructor
assignment
destructor
destructor

Changing the initialization from the assignment in the constructor body to the initializer list replaces the calls to the default constructor plus assignment operator with a call to the copy constructor:

    bar(foo const & value) : f(value) { }

Adding the preceding line of code produces the following output:

default constructor 
copy constructor
destructor
destructor

For those reasons, at least for other types than the built-in types (such as bool, char, int, float, double or pointers), you should prefer the constructor initializer list. However, to be consistent with your initialization style, you should always prefer the constructor initializer list when that is possible. There are several situations when using the initializer list is not possible; these include the following cases (but the list could be expanded with other cases):

  • If a member has to be initialized with a pointer or reference to the object that contains it, using the this pointer in the initialization list may trigger a warning with some compilers that it is used before the object is constructed.
  • If you have two data members that must contain references to each other.
  • If you want to test an input parameter and throw an exception before initializing a non-static data member with the value of the parameter.

Starting with C++11, non-static data members can be initialized when declared in the class. This is called default member initialization because it is supposed to represent initialization with default values. Default member initialization is intended for constants and for members that are not initialized based on constructor parameters (in other words members whose value does not depend on the way the object is constructed):

    enum class TextFlow { LeftToRight, RightToLeft }; 

struct Control
{
const int DefaultHeight = 20;
const int DefaultWidth = 100;

TextFlow textFlow = TextFlow::LeftToRight;
std::string text;

Control(std::string t) : text(t)
{}
};

In the preceding example, DefaultHeight and DefaultWidth are both constants; therefore, the values do not depend on the way the object is constructed, so they are initialized when declared. The textFlow object is a non-constant non-static data member whose value also does not depend on the way the object is initialized (it could be changed via another member function), therefore, it is also initialized using default member initialization when it is declared. text, on the other hand, is also a non-constant non-static data member, but its initial value depends on the way the object is constructed and therefore it is initialized in the constructor's initializer list using a value passed as an argument to the constructor.

If a data member is initialized both with the default member initialization and constructor initializer list, the latter takes precedence and the default value is discarded. To exemplify this, let's again consider the foo class earlier and the following bar class that uses it:

    struct bar 
{
foo f{"default value"};

bar() : f{"constructor initializer"}
{
}
};

bar b;

The output differs, in this case, as follows, because the value from the default initializer list is discarded, and the object is not initialized twice:

constructor
constructor initializer
destructor
Using the appropriate initialization method for each member leads not only to more efficient code but also to better organized and more readable code.

Controlling and querying object alignment

C++11 provides standardized methods for specifying and querying the alignment requirements of a type (something that was previously possible only through compiler-specific methods). Controlling the alignment is important in order to boost performance on different processors and enable the use of some instructions that only work with data on particular alignments. For example, Intel SSE and Intel SSE2 require 16 bytes alignment of data, whereas for Intel Advanced Vector Extensions (or Intel AVX), it is highly recommended to use 32 bytes alignment. This recipe explores the alignas specifier for controlling the alignment requirements and the alignof operator that retrieves the alignment requirements of a type.

Getting ready

You should be familiar with what data alignment is and the way the compiler performs default data alignment. However, basic information about the latter is provided in the How it works... section.

How to do it...

  • To control the alignment of a type (both at the class level or data member level) or an object, use the alignas specifier:
        struct alignas(4) foo 
{
char a;
char b;
};
struct bar
{
alignas(2) char a;
alignas(8) int b;
};
alignas(8) int a;
alignas(256) long b[4];
  • To query the alignment of a type, use the alignof operator:
        auto align = alignof(foo);

How it works...

Processors do not access memory one byte at a time, but in larger chunks of powers of twos (2, 4, 8, 16, 32, and so on). Owing to this, it is important that compilers align data in memory so that it can be easily accessed by the processor. Should this data be misaligned, the compiler has to do extra work for accessing data; it has to read multiple chunks of data, shift, and discard unnecessary bytes and combine the rest together.

C++ compilers align variables based on the size of their data type: 1 byte for bool and char, 2 bytes for short, 4 bytes for int, long and float, 8 bytes for double and long long, and so on. When it comes to structures or unions, the alignment must match the size of the largest member in order to avoid performance issues. To exemplify, let's consider the following data structures:

    struct foo1    // size = 1, alignment = 1 
{
char a;
};

struct foo2 // size = 2, alignment = 1
{
char a;
char b;
};

struct foo3 // size = 8, alignment = 4
{
char a;
int b;
};

foo1 and foo2 have different sizes, but the alignment is the same--that is, 1--because all data members are of type char, which has a size of 1. In structure foo3, the second member is an integer, whose size is 4. As a result, the alignment of members of this structure is done at addresses that are multiples of 4. To achieve that, the compiler introduces padding bytes. The structure foo3 is actually transformed into the following:

    struct foo3_ 
{
char a; // 1 byte
char _pad0[3]; // 3 bytes padding to put b on a 4-byte boundary
int b; // 4 bytes
};

Similarly, the following structure has a size of 32 bytes and an alignment of 8; that is because the largest member is a double whose size is 8. This structure, however, requires padding in several places to make sure that all members can be accessed at addresses that are multiples of 8:

    struct foo4 
{
int a;
char b;
float c;
double d;
bool e;
};

The equivalent structure created by the compiler is as follows:

    struct foo4_ 
{
int a; // 4 bytes
char b; // 1 byte
char _pad0[3]; // 3 bytes padding to put c on a 8-byte boundary
float c; // 4 bytes
char _pad1[4]; // 4 bytes padding to put d on a 8-byte boundary
double d; // 8 bytes
bool e; // 1 byte
char _pad2[7]; // 7 bytes padding to make sizeof struct multiple of 8
};

In C++11, specifying the alignment of an object or type is done using the alignas specifier. This can take either an expression (an integral constant expression that evaluates to 0 or a valid value for an alignment), a type-id, or a parameter pack. The alignas specifier can be applied to the declaration of a variable or a class data member that does not represent a bit field, or to the declaration of a class, union, or enumeration. The type or object on which an alignas specification is applied will have the alignment requirement equal to the largest, greater than zero, expression of all alignas specifications used in the declaration.

There are several restrictions when using the alignas specifier:

  • The only valid alignments are the powers of two ( 1, 2, 4, 8, 16, 32, and so on). Any other values are illegal, and the program is considered ill-formed; that doesn't necessarily have to produce an error, as the compiler may choose to ignore the specification.
  • An alignment of 0 is always ignored.
  • If the largest alignas on a declaration is smaller than the natural alignment without any alignas specifier, then the program is also considered ill-formed.

In the following example, the alignas specifier is applied on a class declaration. The natural alignment without the alignas specifier would have been 1, but with alignas(4) it becomes 4:

    struct alignas(4) foo 
{
char a;
char b;
};

In other words, the compiler transforms the preceding class into the following:

    struct foo 
{
char a;
char b;
char _pad0[2];
};

The alignas specifier can be applied both on the class declaration and the member data declarations. In this case, the strictest (that is, largest) value wins. In the following example, member a has a natural size of 1 and requires an alignment of 2; member b has a natural size of 4 and requires an alignment of 8, therefore, the strictest alignment would be 8. The alignment requirement of the entire class is 4, which is weaker (that is, smaller) than the strictest required alignment and therefore it will be ignored, though the compiler will produce a warning:

    struct alignas(4) foo 
{
alignas(2) char a;
alignas(8) int b;
};

The result is a structure that looks like this:

    struct foo 
{
char a;
char _pad0[7];
int b;
char _pad1[4];
};

The alignas specifier can also be applied on variables. In the next example, variable a, that is an integer, is required to be placed in memory at a multiple of 8. The next variable, the array of 4 a, that is an integer, is required to be placed in memory at a multiple of 8. The next variable, the array of 4 longs, is required to be placed in memory at a multiple of 256. As a result, the compiler will introduce up to 244 bytes of padding between the two variables (depending on where in memory, at an address multiple of 8, the variable a is located):

    alignas(8)   int a;   
alignas(256) long b[4];

printf("%pn", &a); // eg. 0000006C0D9EF908
printf("%pn", &b); // eg. 0000006C0D9EFA00

Looking at the addresses, we can see that the address of a is indeed a multiple of 8, and the address of b is a multiple of 256 (hexadecimal 100).

To query the alignment of a type, we use the alignof operator. Unlike sizeof, this operator can only be applied to type-ids, and not on variables or class data members. The types on which it can be applied can be complete types, an array type, or a reference type. For arrays, the value returned is the alignment of the element type; for references, the value returned is the alignment of the referenced type. Here are several examples:

Expression Evaluation
alignof(char) 1, because the natural alignment of char is 1
alignof(int) 4, because the natural alignment of int is 4
alignof(int*) 4 on 32-bit, 8 on 64-bit, the alignment for pointers
alignof(int[4]) 4, because the natural alignment of the element type is 4
alignof(foo&) 8, because the specified alignment for class foo that is the referred type (as shown in the last example) was 8

Using scoped enumerations

Enumeration is a basic type in C++ that defines a collection of values, always of an integral underlying type. Their named values, that are constant, are called enumerators. Enumerations declared with keyword enum are called unscoped enumerations and enumerations declared with enum class or enum struct are called scoped enumerations. The latter ones were introduced in C++11 and are intended to solve several problems of the unscoped enumerations.

How to do it...

  • Prefer to use scoped enumerations instead of unscoped ones.
  • In order to use scoped enumerations, you should declare enumerations using enum class or enum struct:
        enum class Status { Unknown, Created, Connected };
Status s = Status::Created;
The enum class and enum struct declarations are equivalent, and throughout this recipe and the rest of the book, we will use enum class.

How it works...

Unscoped enumerations have several issues that are creating problems for developers:

  • They export their enumerators to the surrounding scope (for which reason, they are called unscoped enumerations), and that has the following two drawbacks: it can lead to name clashes if two enumerations in the same namespace have enumerators with the same name, and it's not possible to use an enumerator using its fully qualified name:
        enum Status {Unknown, Created, Connected};
enum Codes {OK, Failure, Unknown}; // error
auto status = Status::Created; // error
  • Prior to C++ 11, they could not specify the underlying type that is required to be an integral type. This type must not be larger than int, unless the enumerator value cannot fit a signed or unsigned integer. Owing to this, forward declaration of enumerations was not possible. The reason was that the size of the enumeration was not known since the underlying type was not known until values of the enumerators were defined so that the compiler could pick the appropriate integer type. This has been fixed in C++11.
  • Values of enumerators implicitly convert to int. That means you can intentionally or accidentally mix enumerations that have a certain meaning and integers (that may not even be related to the meaning of the enumeration) and the compiler will not be able to warn you:
        enum Codes { OK, Failure }; 
void include_offset(int pixels) {/*...*/}
include_offset(Failure);

The scoped enumerations are basically strongly typed enumerations that behave differently than the unscoped enumerations:

  • They do not export their enumerators to the surrounding scope. The two enumerations shown earlier would change to the following, no longer generating a name collision and being possible to fully qualify the names of the enumerators:
        enum class Status { Unknown, Created, Connected }; 
enum class Codes { OK, Failure, Unknown }; // OK
Codes code = Codes::Unknown; // OK
  • You can specify the underlying type. The same rules for underlying types of unscoped enumerations apply to scoped enumerations too, except that the user can specify explicitly the underlying type. This also solves the problem with forward declarations since the underlying type can be known before the definition is available:
        enum class Codes : unsigned int; 

void print_code(Codes const code) {}

enum class Codes : unsigned int
{
OK = 0,
Failure = 1,
Unknown = 0xFFFF0000U
};
  • Values of scoped enumerations no longer convert implicitly to int. Assigning the value of an enum class to an integer variable would trigger a compiler error unless an explicit cast is specified:
        Codes c1 = Codes::OK;                       // OK 
int c2 = Codes::Failure; // error
int c3 = static_cast<int>(Codes::Failure); // OK
Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Explore the most important language and library features of C++17, including containers, algorithms, regular expressions, threads, and more,
  • Get going with unit testing frameworks Boost.Test, Google Test and Catch,
  • Extend your C++ knowledge and take your development skills to new heights by making your applications fast, robust, and scalable.

Description

C++ is one of the most widely used programming languages. Fast, efficient, and flexible, it is used to solve many problems. The latest versions of C++ have seen programmers change the way they code, giving up on the old-fashioned C-style programming and adopting modern C++ instead. Beginning with the modern language features, each recipe addresses a specific problem, with a discussion that explains the solution and offers insight into how it works. You will learn major concepts about the core programming language as well as common tasks faced while building a wide variety of software. You will learn about concepts such as concurrency, performance, meta-programming, lambda expressions, regular expressions, testing, and many more in the form of recipes. These recipes will ensure you can make your applications robust and fast. By the end of the book, you will understand the newer aspects of C++11/14/17 and will be able to overcome tasks that are time-consuming or would break your stride while developing.

Who is this book for?

If you want to overcome difficult phases of development with C++ and leverage its features using modern programming practices, then this book is for you. The book is designed for both experienced C++ programmers as well as people with strong knowledge of OOP concepts.

What you will learn

  • Get to know about the new core language features and the problems they were intended to solve
  • Understand the standard support for threading and concurrency and know how to put them on work for daily basic tasks
  • Leverage C++'s features to get increased robustness and performance
  • Explore the widely-used testing frameworks for C++ and implement various useful patterns and idioms
  • Work with various types of strings and look at the various aspects of compilation
  • Explore functions and callable objects with a focus on modern features
  • Leverage the standard library and work with containers, algorithms, and iterators
  • Use regular expressions for find and replace string operations
  • Take advantage of the new filesystem library to work with files and directories
  • Use the new utility additions to the standard library to solve common problems developers encounter including string_view, any , optional and variant types
Estimated delivery fee Deliver to Ecuador

Standard delivery 10 - 13 business days

$19.95

Premium delivery 3 - 6 business days

$40.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : May 15, 2017
Length: 590 pages
Edition : 1st
Language : English
ISBN-13 : 9781786465184
Category :
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Ecuador

Standard delivery 10 - 13 business days

$19.95

Premium delivery 3 - 6 business days

$40.95
(Includes tracking information)

Product Details

Publication date : May 15, 2017
Length: 590 pages
Edition : 1st
Language : English
ISBN-13 : 9781786465184
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 158.97
Modern C++ Programming Cookbook
$54.99
Mastering C++ Multithreading
$48.99
Mastering C++ Programming
$54.99
Total $ 158.97 Stars icon

Table of Contents

12 Chapters
Learning Modern Core Language Features Chevron down icon Chevron up icon
Working with Numbers and Strings Chevron down icon Chevron up icon
Exploring Functions Chevron down icon Chevron up icon
Preprocessor and Compilation Chevron down icon Chevron up icon
Standard Library Containers, Algorithms, and Iterators Chevron down icon Chevron up icon
General Purpose Utilities Chevron down icon Chevron up icon
Working with Files and Streams Chevron down icon Chevron up icon
Leveraging Threading and Concurrency Chevron down icon Chevron up icon
Robustness and Performance Chevron down icon Chevron up icon
Implementing Patterns and Idioms Chevron down icon Chevron up icon
Exploring Testing Frameworks Chevron down icon Chevron up icon
Bibliography Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
(7 Ratings)
5 star 42.9%
4 star 42.9%
3 star 0%
2 star 0%
1 star 14.3%
Filter icon Filter
Top Reviews

Filter reviews by




John Dubchak Jan 31, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I am enjoying this book very much. The recipes are succinct, well-written, to the point and tell you what you need to know, why and without any extra fluff.Highly recommended for those “C++ Programmers” still writing C++98 code - time to modernize.
Amazon Verified review Amazon
Plotnus Dec 07, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This is a great book. This is a readable book. It's not as dry and boring as alternatives. It is not about memorizing 'trivia'. For these reasons, this is my favorite C++ book and one I recommend to my friends.-------------I bought this book for interview prep. It's now my favorite book on modern C++.My Background: I am a game programmer who has come to greatly dislike C++.I feel that C++ is a 'trivia' language. By this, I mean to be a good C++ programmer you need to understand and know loads of trivia. It is a language for pedants. Most C++ books cater to this approach. One example is Scott Myers books which introduce 90 'tips'. You can also find this in the workplace when coders quote the standard. I really dislike the 'trivia' aspect of being a good C++ programmer and see it as a failing of the language. C++ makes things complicated.This book helps boil them down. It's not about trivia. It's about examples and explaining what is going on with C++ and being able to use it. It's back to base principles.Each chapter has the sections: "Getting Ready", "How to do it", "How it Works", and "There's more...""Getting Ready" - this gives you about a paragraph of background and primes your mind for the topic."How to do it" - shows you examples of using or doing the thing being discussed. Prepares you for using the topic on your own. This also gives you examples you can play with on your own computer."How it works" - goes into a few pages of detail about the implementation. This is great because by understanding the implementation you can avoid many of the pitfalls."There's more" - gives additional detail.So, why is this my favorite C++ book?I feel it frees me from the 'trivia' prevalent in many C++ books. By showing examples and talking about the implementation it prepares me to reason about what is going on instead of relying on "Item 35" or some other hard to remember fact about proper C++ usage.
Amazon Verified review Amazon
Miaw May 12, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I am really happy that I own this book and have read it through. Before reading this book I also had some exposure to modern C++ standard/techniques, but it just seemed very intimidating with the enormous amount of new information and philosophy. Also the standard has changed rapidly from one version to another, I was just frustrated about the fast upgrade and felt it is really hard to keep up while attempting to absorb the new ideas. With this book it all started to change, I am really surprised it covers pretty much all the stuff you need to know, or at least gives you enough hints about how to further explore into this new world. After reading this book I feel a lot more confident on new C++ and I have to say it helps me a lot on my work too(I just transitioned from an environment of C++98 to a new place where everything is C++11/14/17 with heavy use of metaprogramming/templates). It even shows you some really cool design patterns and testing framework which really comes in handy, at least for me.I am also surprised it explains well on some really hard/new subjects with fairly limited paragraphs such as memory models used in atomic library and enable_if where both deserve to have their own books. If anything I'd say it probably fails a bit short on move semantics and the use of decltype/declval which in my opinion are also very important stuff in the new standard.Overall I am really satisfied and I feel happy and a lot more knowledgeable when I finished reading it. Highly recommended to all of you who want to catch up on this new wave of C++.
Amazon Verified review Amazon
S. Ghiassy Dec 18, 2017
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Very good book , helps you with new C++ Standards and coding style. Would highly recommend it to all C++ Programmers, from novice to experienced.
Amazon Verified review Amazon
Bartek F. Jun 15, 2017
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Disclaimer: I got a free copy from Packt Publishing.Pros: * Clear structure * Cookbook style, so read what you need * Chapters usually starts with some basic recipes and then increase the level of complexity. * Concise examples and details how it works, so not just functions headers. * Modern coding standard, even with C++17 stuff! * C++11, C++14 and C++17 - with clear distinction, an explanation what have changed, etc. * It doesn't have much of 'intro to C++', so you can just jump into intermediate topics! It's not another basic beginner's book. * There are useful 'tips' here and thereCons:* A few typos, repetitions* Chapter about unit testing frameworks could be shorter, but maybe other devs find it useful.* Some recipes are questionable: but that depends on the view/experience. For example: using bitsets. I'd like to see more about performance in the performance chapter.Overall, I like the book. With its clear structure and well-written recipes, it's a great addition to any C++ bookshelf. It's well suited for the target audience: even if you're an expert you'll get a chance to refresh your knowledge and update it with C++14/C++17 content. And If you've just finished some beginner book, you'll find here topics that will move you forward.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the digital copy I get with my Print order? Chevron down icon Chevron up icon

When you buy any Print edition of our Books, you can redeem (for free) the eBook edition of the Print Book you’ve purchased. This gives you instant access to your book when you make an order via PDF, EPUB or our online Reader experience.

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela