cpp ref


Guide

sizeof(array)

int print_size1(int a[], int n)
{// int add(int*, int)
    std::cout<< sizeof(a) << std::endl; 
    // we get sizeof(int*)
}

int print_size2(int *a, int n)
{// int add(int*, int)
    std::cout<< sizeof(a) << std::endl;
    // we get sizeof(int*)
}

#define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0])) 

void test_array()
{
    int a[5] = {1,2,3,4,5};
    int n = N_ELEMENTS(a); 
    std::cout<<"num  = "<< n << std::endl; // 5
    std::cout<< sizeof(int) << std::endl; // int size
    std::cout<< sizeof(int*) << std::endl; // pointer size
    std::cout<< sizeof(a) << std::endl; // 20
    print_size1(a, 5);
    print_size2(a, 5);
}

An array-type is implicitly converted into pointer type when you pass it in to a function.
int a[]作为函数参数,隐式的转换为int *a.

编译会产生warning.

warning: ‘sizeof’ on array function parameter ‘a’ will return size of ‘int*’ [-Wsizeof-array-argument]
  std::cout<< sizeof(a) << std::endl; // pointer size

char* string

void test_str1()
{
    // warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
    char* str = "Hello";  //Warning

    const char* str1 = "Hello"; // No warning 

    // trying to modify const string literal 
    // gives Runtime error  
    // segmentation fault (core dumped)
    //str[1] = 'o'; 

    cout << str << endl; 
}
/*
Hello常量字符串,存放在静态数据区; 由于字符串常量无需改动,放在静态内存区会提高效率.
*/

void test_str2()
{
    char str1[] = "abc";
    char str2[] = "abc";
    const char str3[] = "abc";
    const char str4[] = "abc";
    const char *str5 = "abc";
    const char *str6 = "abc";
    cout << ( str1 == str2 ) << endl; // 0
    cout << ( str3 == str4 ) << endl; // 0
    cout << ( str5 == str6 ) << endl; // 1

    str1[1] = 'B'; // OK 
    //str3[1] = 'B'; // Compiler ERROR
}
/*
str1,str2,str3,str4是数组变量。它们有各自的内存空间;
而str5,str6是指针,它们指向同样的常量字符串。
*/


const char* return_str()
{
     const char *p="abc";
     return p;
}

void test_str3()
{
     const char *str=NULL; 
     str= return_str();
     printf("%s\n", str); // abc
}
/*
由于"abc"是一个字符串常量,存放在静态数据区。把该字符串常量存放的静态数据区的首地址赋值给了指针。
所以return_str函数退出时,该字符串常量所在内存不会被回收。故可以通过指针顺利无误的訪问。
*/

char* return_str2()
{
     char p[] ="abc";
     return p; // warning: address of local variable ‘p’ returned [-Wreturn-local-addr]
}

void test_str4()
{
     char *str=NULL; 
     str= return_str2();
     printf("%s\n", str); // null
}
/*
"abc"是一个字符串常量,存放在静态数据区。
可是把一个字符串常量赋值给了一个局部变量(char []型数组),该局部变量存放在栈中,该数组空间中也存储"abc"的一份拷贝。

也就是说`char p[]="abc";`这条语句让"abc"这个字符串在内存中有两份拷贝,一份在动态分配的栈中,还有一份在静态存储区。
这是与前者return_str1最本质的差别,当return_str2函数退出时,栈要清空,局部变量的内存也被清空了。
所以这时的函数返回的是一个已被释放的内存地址。所以打印出来的是null。
*/


char* return_str3()
{
     static char p[]="abc"; //p存放在静态存储区,内容为abc
     return p;
}

void test_str5()
{
     char *str=NULL; 
     str= return_str3();
     printf("%s\n", str); // abc
}
/*
如果函数的返回值非要是一个局部变量的地址,那么该局部变量一定要申明为static类型。
*/

char*-vs-stdstring
const string

NULL vs nullptr

nullptr
NULL (void *)0

  • convert to integer
  • pointer

nullptr keyword

  • pointer
  • CAN NOT convert to integer
  • nullptr is convertible to bool.

const vs non-const

Use const whenever possible.

将某些东西声明为const可以帮助编译器侦测出错误的用法。const可以被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
当const和non-const成员函数有实质等价的实现时,令non-const版本去调用const版本可以避免代码重复。反之则不可。

code

class TextBlock {
public:
...
    //const:和原先一样
    const char& operator[] (std::size_t position) const 
    { 
        ...
        ...
        ...
        return text[position]; 
    }

    //non-const:发生区别,直接调用了const op[]
    char& operator[] (std::size_t position)
    {
        return   //直接return
            const_cast<char&>(  //(3)将op[]返回值的const移除
                static_cast<const TextBlock&>(*this)    //(1)为*this加上const
                    [position]    //(2)调用const op[]
                );
            }
        ...
    }

两次转型:
第一次,用来为this添加 const,将this从其原始类型TextBlock& 转换为const TextBlock&,使得接下来调用operator[]是可以条用const的版本,使用static_cast
第二次,则是从const operator[]的返回值中移除const,利用const_cast来完成。

static

  • static: internal linkage
  • extern: external linkage

extern

extern

extern is present by default with C functions.
Since the declaration can be done any number of times and definition can be done only once

volatile

volatile
volatile cnblogs

volatile 异变的,告诉compiler这个值可能会在当前线程外部被改变,因此不要进行优化,每次都从ram地址读取,而不要从register读取缓存的副本。

Internal Linkage and External Linkage in C

internal linkage and external linkage
what-is-external-linkage-and-internal-linkage

scope is a property handled by compiler, whereas linkage is a property handled by linker.
external linkage means the symbol (function or global variable) is accessible throughout your program and internal linkage means that it’s only accessible in one translation unit.
You can explicitly control the linkage of a symbol by using the extern and static keywords. If the linkage isn’t specified then the default linkage is extern for non-const symbols and static (internal) for const symbols.
The keyword static plays a double role. (1) When used in the definitions of global variables, it specifies internal linkage. (2) When used in the definitions of the local variables, it specifies that the lifetime of the variable is going to be the duration of the program instead of being the duration of the function.

constexpr

constexper

constexpr is a feature added in C++ 11. The main idea is performance improvement of programs by doing computations at compile time rather than run time.

constexpr vs inline functions

Both are for performance improvements, inline functions are request to compiler to expand at compile time and save time of function call overheads. In inline functions, expressions are always evaluated at run time. constexpr is different, here expressions are evaluated at compile time.

vtable and vptr

virtual-functions-and-runtime-polymorphism
what-are-vtable-and-vptr
calling-virtual-methods-in-constructordestructor-in-cpp

It is highly recommended to avoid calling virtual methods from constructor/destructor.

virtual-function-table
class-memory-layout

Virtual Constructor

Virtual Constructor

Virtual Constructor, NO
Can we make a class constructor virtual in C++ to create polymorphic objects? No. C++ being static typed (the purpose of RTTI is different) language, it is meaningless to the C++ compiler to create an object polymorphically. The compiler must be aware of the class type to create the object. In other words, what type of object to be created is a compile time decision from C++ compiler perspective. If we make constructor virtual, compiler flags an error.

Virtual Destructor

Virtual Destructor

Deleting a derived class object using a pointer to a base class that has a non-virtual destructor results in undefined behavior.

Advanced

thread

  • pass by value by default
  • pass by ref: std::ref(variable)

Reference

History

  • 20190429: created.

Author: kezunlin
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source kezunlin !
评论
  TOC