Effective C++ Programming) Part 1
This post was migrated from Tistory. You can find the original here.
When a function is called with an argument whose type doesn’t match the parameter type, C++ doesn’t throw an error (it just gives a warning) — it performs an automatic type conversion, and data can be lost as a result.
Inline functions
1
2
3
inline int add(int a, int b) {
return a + b;
}
You can define a function using the inline keyword.
When you use inline, instead of the function actually being called, the compiler tries to insert the function’s code directly at the call site. This removes call overhead and can reduce execution time.
However, this increases code size, and inline is only a suggestion to the compiler — it may choose not to honor it.
Macro functions
1
2
3
4
5
6
7
8
9
#define SQUARE(x) ((x) * (x))
...
void main(void)
{
cout << SQUARE(3.5) << endl;
cout << SQUARE(4.1234) << endl;
cout << SQUARE(3) << endl;
}
A macro function isn’t tied to any particular data type, so no data loss occurs no matter what type is passed in.
What const means
const int num = 10; => makes the variable num a constant
const int* ptr = &val; => the value of val cannot be changed through the pointer ptr
int* const ptr = &val; => the pointer ptr itself is constant
const int* const ptr = &val; => the pointer ptr itself is constant, and the value of val cannot be changed through ptr
Call by reference using references
1
void Test(int& ref) { .... };
A reference must be initialized with a variable at the moment it’s declared.
But function parameters are only initialized once the function is actually called.
So the parameter declaration above isn’t “uninitialized” — it means the reference is initialized with whatever argument is passed in when the function is called.
1
2
int num = 1;
TestFunc(num);
In C, with void TestFunc(int a) { .... }, num can’t be changed by the call.
In C++, however, if the function is declared as void TestFunc(int& a) { .... }, num can be changed.
That’s why, in C++, you need to check the function prototype — if it’s defined as void TestFunc(const int &a) { .... }, then the value can’t be changed through the reference a.
When the return type is a reference
You should never return a local variable by reference.
Be careful: sometimes the output looks perfectly normal because it happens to reference leftover data that hasn’t been destroyed yet — but that’s not something you can rely on.
1
2
3
4
5
6
7
8
9
10
11
int& RetuRefFunc(int n)
{
int num = 20;
num += n;
return num;
}
void main(void)
{
int& ref = RetuRefFunc(10);
}
In a case like this, the compiler only issues a warning.
Something like: “returning address of local variable or temporary: num.”
Temporary variables, references to constants, and const references
const int& ref = 3;
When you use a const reference to reference a constant, a temporary variable is created behind the scenes. The constant 3 is stored in that temporary location, and the reference ends up referring to it.
1
2
3
4
int Test(const& int a, const& int b)
{
return a + b;
}
Why go to the trouble of creating a temporary variable just to allow references to constants? Supposedly it’s so you can call the function with literal constants like Test(3, 50) instead of only Test(num1, num2).
That said, testing this in current Visual Studio 2019 shows that you can pass constants as arguments even without using a const reference.
Accessing the heap without pointer arithmetic
1
2
3
4
5
int *ptr = new int;
int &ref = *ptr;
ref = 20;
cout << *ptr; // 20
delete ptr;
