C++备忘录067:Initialization in C++, the incomplete and inaccurate guide

We get a mess, the mess get worse, so it’s time to switch to a new language. – Nicolai Josuttis

在这里插入图片描述

Initialization of C++ is Bonkers

Intializer may be one the the following

  1. ()
  2. =
  3. {}

Depending on the context, it may invoke:

  1. Default initialization
  2. Copy initialization
  3. Value initialization
  4. Aggregate initialization
  5. Direct initialization
  6. List initialization

Different C++ standard may have different rules

Default initialization

This is the initialization performed when a variable is constructed with no initializer.

Syntax

T object;
new T;
new T(); // until C++03

Examples & Traps

int i;
int j = i;  // UB

However, unsigned char is an exception

unsigned char i;
unsigned char j = i; // no undefined

For struct in C/C++, and class in C++, default initalization does not initialize anything by default

struct S {
   
    int i;
};

S s;    // calls implicit default ctor
int j = s.i;    // UB
class C {
   
    int i;
public:
    C() {
   }
    int getI() {
    return i; }
};

C c;
int j = c.getI();   // UB

If T is a const-qualified type, it must be a class type with a user-provided default constructor.

A constructor is user-provided if it is user-declared and not explicitly defaulted on its first declaration.

const int i;    // Error

struct S {
   
    int i;
};
const S s;      // Error

struct X {
   
    X() = default;      // user-declared, but not user-provided
    int i;
};
const X x;      // Error

struct Y {
   
    Y();
    int i;
};
Y::Y() = default;
const Y y;      // OK

Summary

  • built-in types: uninitialized, UB on access
  • class types: default constructor

To avoid UB, use Direct Member Initialization whenever possible

struct S {
   
    int i = 0;
    W w = {
   };
};

Copy initialization

Initializes an object from another object

Syntax

T object = other;
T object = {
   other}; // until C++11
T array[N] = {
   other};
f(other)
return other;
throw object;
catch (T object)
  • initializer starts with =, or
  • Passing arguments by value, or
  • Returning by value, or
  • Throwing/Catching exceptions by value

Summary

  • Copy initialization is never an assignment

  • If type don’t match, copy initialization performs a conversion sequence, but explicit ctors are not participate

    struct S {
         
    	explicit S(int);
    };
    
    void foo(const S &);
    
    foo(42);	// error
    
    S s1(42);
    S s2{
         42};
    S s3 = 42;	// error
    S s4 = {
         42};	// error
    
  • The implicit conversion must produce T directly from the initializer.

    struct S {
         
        S(std::string);
    };
    S s1 = "hello"    // Error, no conversion from const char [6] to std::string
    S s2 = ("hello"); // ditto, only const char * to std::string
    
    S s3("hello");    // OK
    S s4 = {
         "hello"}; // OK, different rules apply
    S s5{
         "hello"};    // OK
    

Aggregate intialization

Initializes an aggregate from braced-init-list

Syntax

T object = {
   arg1, arg2, ...};
T object {
   arg1, arg2, ...}; // since C++11
  • An array, or
  • A class (struct/union), that has
    • C++98
      • no user-declared ctors
      • no private or protected non-static data members
      • no base class
      • no virtual functions
    • C++11/14
      • no user-provided ctors
      • no private or protected non-static data memebers
      • no base class
      • no virtual functions
      • no default member initializers
    • C++17
      • no user-provided, explicit, or inherited ctors
      • no private or protected non-static data members
      • no virtual, private, or prtected base class
      • no virtual functions

Examples & Traps

Aggregate definition got relaxed standard after standard

struct Data {
   
	std::string name;
	double value;
};

struct DV: Data {
   	// before C++17, this is a class with default ctor
	bool used;		// since C++17, this is an aggregate
	void print() const;
};

DV u;	// value and used are undefined
DV v{
   };	// value and used with 0 and false
DV v{
   {
   "hello", 3}, true};
DV v{
   "hello", 3, true};

Aggregate initialization copy init its member

struct S {
   
    explicit S(int);
};

struct A {
   
    S s1, s2;
};

S s = {
   3, 4}; // Error, because S(int) is explicit
struct S {
   
    explicit S(int);
    S(double);
};

S s = {
   3, 4}; // calls S(double)

Aggregate initialzation zero init its remaining elements

struct S {
   
    int i, j;
};

S s = {
   1};         // s.i = 1, s.j = 0

int a[100] = {
   };    // all zeros

Brace elision

struct S {
   
    int i, j;
};

struct A {
   
    S s;
    int k;
};

A a = {
   1, 2}; // A a = {
   {1, 2}, 0}
struct S {
   
	S() = delete; // user-declared, but not user-provided, so since c++11, it is an aggregate
};

S s1;	// error
// WTF of the month -- on Nicolai Josuttis twitter
// Or a nice way to force to initialize an aggregate
S s2{
   };	// ok since c++11, fixed in C++20
struct S {
   
	int i = 0;
	S(int) = delete;
};

S s1(3); // error
S s2{
   3}; // ok since c++11, fixed in C++20

std::array is an aggregate, it can be ridiculous

  • Without intializaton elements might have undefined values
  • Nested intializations need an additional pair of braces
std::array<int, 10> a;      // values are undefined
std::array<int, 10> b{
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值