文章目录
const in C++ const in C++ const in C++
Questions 32 ~ 41 from Daily C++ Interview
const variables
The rule of thumb is to mark variables const when you are sure that they don’t change, because the compiler can perform more optimizations on const variables. This is especially true for gloabal variables (if you ever use global variables at all) because anyone can modify global variables and there is easily confusion.
constness of a member function
If a member function has overloaded versions where one is const and the other is not, the compiler would choose which one to invoke based on the constness of the object. It has nothing to do with the constness of the variable returned.
class myClass {
int foo() {
return 1;
}
int foo() const {
return 2;
}
};
myClass c1;
const myClass c2;
int a = c1.foo(); // 1
const b = c1.foo(); // 1
int x = c2.foo(); // 2
int y = c2.foo(); // 2
constness of a member variable
The biggest implication of using constnes on member variables is that you cannot copy/move the object.
Since member variables are set as const, their assignment operators are deleted, since no one should assign to them after initialization. However, the copy/move assignment operators are also deleted, so when you try to copy/move the object, you implicitly copy/move all of its member variables and that fails.
constness of a return value
returning const by value
You can use const on a function return type, either by value or by reference. There is basically no reason to return const by value, because it only hinders optimization. You can use i as if there is no const, but this hinders copy elision or NRVO. There is a copy at int i = c.foo(), rather than a move.
class myClass {
const int foo() {
int x = 1;
return x;
}
};
myClass c;
int i = c.foo();
i = 5; // OK, i is not const although foo() returns const
returning const by reference
Returning const by reference makes sense when an object returns a const reference to its members. No expensive copying. The object retains ownership of its data and callers cannot modify its data.
class TradeEngine {
public:
const Order& getOrder(OrderId id) {
return orders_[id];
}
private:
std::vector<Order> orders_;
};
Don’t return a reference of a local variable in a function because it will dangle. Constness doesn’t change that.
returning const by pointer
There are two ways you can dress a pointer as const. The constness either refers to the pointed object or the pointer itself. It makes sense to return a pointer that doesn’t allow modifying its pointed object. But it makes no sense to return a const pointer, because the constness will be discarded.
class MyClass {
private:
int x;
public:
const int* foo1() { return &x; } // makes sense
int* const foo2() { return &x; } // useless
};
MyClass c;
auto* p1 = c.foo1();
*p1 = 5; // Error: Good. Cannot modify the variable
auto* p2 = c.foo2();
int a = 5;
p2 = &a; // I can still modify p2 anyways, so the constness has no effect
constness of objects as function arguments
We shall make const reference the default for taking objects as function arguments. When we do need to modify the original object, make it a reference without const. And when we want a copy of the object inside the function, take it by value. But never take an object by const value because it simply adds overhead without benefits.
constness in function declaration and definition
The constness in function parameters in declarations only implies that the function won’t modify what you pass in, but it can. In other words, even if you declare parameters as const, you can still write non-const versions of that function in its definition.
In the following example, the definition of foo outside the class would match the declaration without error, although the compuler might give a warning.
class MyClass {
public:
void foo(const int x); // declaration
};
void MyClass::foo(int x) {
x = 42; // valid
}
But if we change const int x and int x into reference: const int& x and int& x, the code stops compiling.
consteval and constinit
constexpr is introduced in C++11 for compile time expression evaluation. C++20 introduces consteval and constinit.
consteval
consteval forces (MUST) compile time evaluation of functions, that is, every immediate call must be evaluated at compile time.
consteval int square(int x) {
return x * x;
}
constexpr int a = square(5); // 5 is a constant expression, so OK
int n = 5;
int b = square(n); //ERROR: n is not a constant expression
If in the above case, square() is decorated with constexpr instead of consteval, then the code CAN be evaluated at compile time, rather than a MUST.
constinit
constinit forces static initialization, meaning it guarantees that the initialization happens at compile time. It is used with variables having static or thread storage duration. It does not require that the variable doesn’t change after initialization.