c++静态代码分析_函数参数求值顺序未定义等

追踪内存分配

重载全局new和delete实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "../src/include/local.h"
#define ps(str) std::cout << str << std::endl

struct AllocationMetrics
{
uint32_t TotalAllocated = 0;
uint32_t TotalFreed = 0;

uint32_t CurrentUsage() { return TotalAllocated - TotalFreed; }
};

AllocationMetrics s_AllocationMetrics;

struct Object
{
int x, y, z;
};

void* operator new(size_t size)
{
s_AllocationMetrics.TotalAllocated += size;
std::cout << "Allocating " << size << " bytes\n";
return malloc(size);
}

void operator delete(void* memory,size_t size)
{
s_AllocationMetrics.TotalFreed += size;
free(memory);
}

void PrintMemoryUsage()
{
std::cout << "Memory Usage: " << s_AllocationMetrics.CurrentUsage() << " bytes\n";
}

int main()
{
PrintMemoryUsage();
std::string name = "Cherno";
PrintMemoryUsage();
{
std::unique_ptr<Object> obj = std::make_unique<Object>();
PrintMemoryUsage();
}
PrintMemoryUsage();
std::cin.get();
}

简单区分左右值

注意:std::string& name此参数仅能接收左值,但是加上const,即const std::string &name 此参数既能接收左值又能接收右值,编译器构造一个临时变量(左值),作为参数传递给函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "../src/include/local.h"
#define ps(str) std::cout << str << std::endl

void PrintName(std::string&& name)
{
std::cout << "[Rvalue] " << name << std::endl;
}

void PrintName(const std::string& name)
{
std::cout << "[Lvalue] " << name << std::endl;
}

int main()
{
int i = 10;

std::string firstName = "yan";
std::string lastName = "Chernikov";

std::string fullName = firstName + lastName;
PrintName(fullName);
PrintName(firstName + lastName);

std::cin.get();
}

使用静态代码分析工具PVS-Studio

安装后,在Vs菜单栏->扩展->PVS->check-current-file,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>

struct Entity
{

};

Entity* LoadEntity()
{
return nullptr;
}

int main()
{

Entity* entity = LoadEntity();
if (entity)
{

}

const char* string = "Hello";
char* buffer = new char[strlen(string)];
//strcpy(buffer,string);
memcpy(buffer,string,strlen(string));

uint32_t width = 800, height = 600;
uint32_t* buffer = new uint32_t[width*height];

for (uint32_t y = 0; y < height; y++)
{
for (uint32_t x = 0; x < width; y++)
{
buffer[x + y * width] = 0;
}
}
std::cin.get();
}

上面代码明显错误/优化点:

  1. entity永远为nullptr,分支只能降低程序执行速度
  2. buffer大小分配有问题
  3. 第2层for循环有问题

Argument Evaluation Order(参数求值顺序)

PVS报错:unspecified behavior,The order of argument evaluation is not defined for 'PrintSum' function,Consider inspecting the 'value' variable

c++标准没有指定函数定义的参数的求值顺序

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
void PrintSum(int a, int b)
{
std::cout << a << " + " << b << " = " << (a + b) << std::endl;
}

int main()
{
int value = 0;
PrintSum(value++,value++);
std::cin.get();
}
  1. MSVC 开启c++17选项

    1. Debug模式

    2. Release模式

    的结果都是1+0=1,并且编译没有warning

  2. clang 10.0.0 clang++ prog.cc -Wall -Wextra -std=c++17

    1
    2
    3
    4
    prog.cc:10:16: warning: multiple unsequenced modifications to 'value' [-Wunsequenced]
    PrintSum(value++,value++);
    ^ ~~
    1 warning generated.

    执行结果:0+1=1,貌似是从左到右执行

  3. gcc 9.3.0 g++ prog.cc -Wall -Wextra -I/opt/wandbox/boost-1.73.0/gcc-9.3.0/include -std=c++17

    1
    2
    3
    4
    5
    prog.cc: In function 'int main()':
    prog.cc:10:24: warning: operation on 'value' may be undefined [-Wsequence-point]
    10 | PrintSum(value++,value++);
    | ~~~~~^~
    prog.cc:10:24: warning: operation on 'value' may be undefined [-Wsequence-point]

    执行结果:1+0=1,和MSVC的结果一样