当前位置:网站首页>Weekly tip 142: multi parameter constructors and explicit
Weekly tip 142: multi parameter constructors and explicit
2022-07-26 07:06:00 【-Flying crane-】
As TotW#142 Originally published in 2018 year 1 month 29 Japan
from James Dennett A literary creation
“ Explicit is better than implicit ”——PEP 20
Cut a long story short
Most constructors should be explicit
Introduce
stay C++11 Before ,explicit Keywords are only meaningful for constructors that can be called with a single parameter , And our style guide requires it to be used for such constructors , Lest they act as “ Transform constructor ”. This requirement does not apply to multi parameter constructors . in fact , Style guides used to discourage explicit use of multiparameter constructors , Because it doesn't make any sense . This is no longer the case .
stay C++11 in , Explicit initialization becomes meaningful for copying from a list of curly braces , For example, in use f({1, 2}) Call function void f(std::pair<int, int>) Or initialize variables bad when , Use std::vector<char> bad = {“hello”, “world”};.
wait a minute ! In the last example , Type mismatch . That can't be compiled , Is that OK ? std::vector<std::string> good = {“hello”, “world”}; It's reasonable , But a std::vector<char> Can't hold two std::strings. However, it does compile ( Or at least it can work with all current C++ The compiler compiles together ). What's going on ? After we discuss explicit in detail , Let's talk about it later .
Constructor that changes the type but does not change the value
The compiler can call constructors that are not marked as explicit to create values , There is no need to mention the name of the type . When we have the value we want but the type doesn't match exactly , That's also good —— We have a const char[], We may need a std::string, Or we have two std::strings, We want one std::vector<std::string>, Or we have one int And we want one BigNum. In short , If the values before and after conversion are basically the same , It works well .
// The coordinates of a point in the Cartesian plane, w.r.t. some basis.
class Coordinate2D {
public:
Coordinate2D(double x, double y);
// ...
};
// Computes the Euclidean norm of a given point `p`.
double EuclideanNorm(Coordinate2D p);
// Uses of the non-explicit constructor:
double norm = EuclideanNorm({
3.0, 4.0}); // passing a function argument
Coordinate2D origin = {
0.0, 0.0}; // initializing with `=`
Coordinate2D Translate(Coordinate2D p, Vector2D v) {
return {
p.x() + v.x(), p.y() + v.y()}; // returning a value from a function
}
Through an undeclared constructor Coordinate2D(double, double), We are allowed to {3.0, 4.0} Pass it on to the receiver Coordinate2D Function of parameter . Whereas {3.0, 4.0} It is a completely reasonable value for such an object , Therefore, this availability will not cause confusion .
Constructor to do more
If the output of the constructor is different from its input value , Or it may have prerequisites , It is not a good idea to call constructors implicitly .
Consider a constructor Request(Server*, Connection*) Of Request class . The value of the request object “ yes ” Servers and connections are meaningless —— We can just create a request to use them . It can be downloaded from {server, connection} Construct many semantically different types , For example, response . Such a constructor should be explicit , So we can't {server, connection} Pass to accept the request ( Or respond to ) Function of parameter . under these circumstances , Marking the constructor explicit allows you to name the target type when it is instantiated , So that the code is clearer to readers , And help avoid errors caused by unexpected conversions .
// A line is defined by two distinct points.
class Line {
public:
// Constructs the line passing through the given points.
// REQUIRES: p1 != p2
explicit Line(Coordinate2D p1, Coordinate2D p2);
// Determines whether this line contain a given point `p`.
bool ContainsPoint(Coordinate2D p) const;
};
Line line({
0, 0}, {
42, 1729});
// Computes the gradient of `line`. Returns an infinite value if `line` is
// vertical.
double Gradient(const Line& line);
By setting the constructor Line(Coordinate2D, Coordinate2D) Declare explicit , We can prevent code from passing irrelevant points to Gradient, There is no need to convert them into Line object . A line of “ value ” Not two , Nor is any two points defining a line .
As another example , stay std::unique_ptr Using explicit ownership transfer from the original pointer in can prevent double deletion errors here :
std::vector<std::unique_ptr<int>> v;
int* p = new int(-1);
v.push_back(p); // error: cannot convert int* to std::unique_ptr<int>
// ...
v.push_back(p);
To pass std::unique_ptr , The programmer must explicitly create a , This leaves readers with a visual clue that ownership is shifting . Explicit constructors help record the constraints that the original pointer must have its target .
recommend
- Copy constructors and move constructors should never be explicit .
- Make the constructor explicit , Unless its parameters “ yes ” The value of the newly created object . ( Be careful :Google Style guides currently require that all single parameter constructors be explicit ).
- especially , identification ( Address ) The constructor of a value related type should be explicit . - Impose additional constraints on values ( That is, there are prerequisites ) The constructor of should be explicit . Sometimes these are better implemented as factory functions ( See Tips #42: Factory functions are preferred over initialization methods ).
Conclusion
This technique can be regarded as a tip #88: initialization :=、() and {} The opposite of , It suggests that we start from “ Expected literal value ” Use copy initialization syntax when initializing ( belt =). The advice of this tip is only for tips 88 Omit the explicit when using replication initialization ( Otherwise, it will be prohibited by explicit keywords ).
Last , A warning :C++ The standard library does not always do this . Back to our example ( Mistakenly declared a std::vector<char> Instead of a string container ):
std::vector<char> bad = {
"hello", "world"};
We found that std::vector There is a templating with a pair of iterators “ Range ” Constructors , Here they match and derive the parameter type as const char*. If you apply the recommendations in this tip , Then the constructor will be explicit , because std::vector<char> The value of is not two iterators ( It's a sequence of characters ). in fact ,explicit Was omitted , And this sample code gives undefined behavior , Because the second iterator cannot be accessed from the first iterator .
边栏推荐
- Introduce you to JVM from architecture
- Contents mismatch at: 08000000H (Flash=FFH Required=00H) ! Too many errors to display !
- [arm learning (8) AXF tool analysis]
- NPM command
- "Wei Lai Cup" 2022 Niuke summer multi school training camp 1 supplementary question record (acdgij)
- Leetcode question brushing 1: topic classification
- 20220724 三角函数系的正交性
- one hundred and twenty-three million one hundred and twenty-three thousand one hundred and twenty-three
- Make a chase game with pyGame
- Intention lock
猜你喜欢

强网杯2021 pwn 赛题解析——baby_diary

浅谈eval与assert一句话木马执行区别

7. Reverse integer integer

【硬十宝典】——7.1【动态RAM】DDR硬件设计要点

Drools (2): drools quick start

Common CMD instructions

Curl post request on the server, using postman tool for parameter conversion

Idea -- use @slf4j to print logs
![[arm learning (8) AXF tool analysis]](/img/6c/df2ebb3e39d1e47b8dd74cfdddbb06.gif)
[arm learning (8) AXF tool analysis]

"Niuke | daily question" inverse Polish expression
随机推荐
Basic operations and common functions of MySQL table creation
MySQL table write lock
Question: can't download sh shellcheck Please install it manually and some commands of shell script
NiO implementation
“蔚来杯“2022牛客暑期多校训练营1补题记录(ACDGIJ)
Exclusive lock
敏捷整洁之道
[hard ten treasures] - 7.2 [dynamic RAM] analysis of the difference between DDR4 and DDR3
C # use log4net plug-in to output logs to files
Flame diagram analysis Flink backpressure
【QT】怎样获得QTableView和QTableWidget的行数和列数
基于C51实现led流水灯
SQL shell (PSQL) tool under PostgreSQL
MySql 执行计划
【数据库】CTE(Common Table Expression(公共表表达式))
Database performance test (MySQL)
npm 命令
one hundred and twenty-three million one hundred and twenty-three thousand one hundred and twenty-three
Deep learning learning notes -- solve the problem of slow download of CONDA and pip
NPM command