Document number |
P****R0 |
Date |
2022-09-27 |
Reply-to |
Jarrad J. Waterloo <descender76 at gmail dot com>
|
Audience |
Evolution Working Group (EWG) |
C++ is the next C++
Table of contents
Abstract
Programmer’s, Businesses and Government(s) want C++ to be safer and simpler. This has led some C++
programmers to create new programming languages or preprocessors which again is a new language. This paper discusses using static analysis to make the C++
language itself safer and simpler.
Motivating Examples
Following is a wishlist. Most are optional. While, they all would be of benefit. It all starts with a new repeatable module level attribute that would preferably be applied once in the primary module interface unit
and would automatically apply to it and all module implementation unit
(s). It could also be applied to a module implementation unit
but that would generally be less useful. However, it might aid in gradual migration.
export module some_module_name [[static_analysis("")]];
module some_module_name [[static_analysis("")]];
- It would be ideal if the name member of the
static_analysis
attribute could be passed as either an environment variable and/or command line argument to compilers so it could be used by pipelines to assert the degree of conformance to the defined static analyzer without actually changing the source.
- It would be ideal if compilers could standardize the environment variable name or command line argument name in order to ease tooling.
- It would be ideal if compilers could produce a machine readable report in JSON, YAML or something else so that pipelines could more easily consume the results.
- It would be ideal if compilers could standardize the machine readable report.
The name of the static analyzer are dotted. Unscoped or names that start with std.
, c++.
, cpp.
, cxx.
or c.
are reserved for standardization.
This proposal wants to stardardize two overarching static analyzer names; safer
and modern
.
[[static_analysis("safer")]]
|
The safer analyzer is for safety, primarily memory related. It is for those businesses and programmers who must conform to safety standards.
|
[[static_analysis("modern")]]
|
The safer analyzer is a subset of modern analyzer. The modern analyzer goes beyond just memory and safety concerns. It can be thought of as bleeding edge. It is for those businesses and programmers who commit to safety and higher quality modern code.
|
Neither is concerned about formatting or nitpicking. Both static analyzers only produce errors. They both represent +∞. These are meant for programmers, businesses and governments in which safety takes precedence. When a new version of the standard is released and adds new sub static analyzers than everyone’s code is broken until their code is fixed. These sub static analyzers usually consist of features that have been mostly replaced with some other feature. It would be ideal if the errors produced not only say that the code is wrong but also provide a link to html page(s) maintained by both the C++
teaching group, the authors of the C++ Core Guidelines
and compiler specific errors. These pages should provide example(s) of what is being replaced and by what was it replaced. Mentioning the version of the C++
standard would also be helpful.
All modules can be used even if they don’t use the static_analysis
attribute as this allows gradual adoption.
What are the safer
and modern
analyzers composed of?
These overarching static analyzers are composed of multiple static analyzers which can be used individually to allow a degree of gradual adoption.
Use lvalue references
[[static_analysis("use_lvalue_references")]]
|
use_lvalue_references is a subset of safer .
|
- Any declaration of a pointer is an error.
- Calling any function that has parameters that take a pointer is an error unless the pointer type are “pointer to
const
character type” or “const
pointer to const
character type” and their arguments were string literals.
- string literals are always safe having static storage duration
std::string
and std::string_view
must be creatable at compile time
- Function pointers and member function pointers can still be used.
- Lvalue references, &, can still be used.
WHY?
- A large portion of the C++ community have been programming without pointers for years. Some can go their whole career this way. This proposal just standardise existing practice.
- Modern
C++
has been advocated to programmers in other programming languages who complain about memory issues. This allows us to show them what we have been saying for decades.
- Over half of our memory related issues gets hashed away.
- Pointers have largely been replaced with the following:
lvalue references
|
1985: Cfront 1.0
|
STL
|
1992
|
std::unique_ptr , std::shared_ptr , std::weak_ptr , std::reference_wrapper , std::make_shared
|
C++11
|
std::make_unique
|
C++14
|
std::string_view , std::optional , std::any , std::variant
|
C++17
|
std::make_shared support arrays, std::span
|
C++20
|
The C++ Core Guidelines
identifies issues that this feature helps to mitigate.
P.4: Ideally, a program should be statically type safe
P.6: What cannot be checked at compile time should be checkable at run time
P.7: Catch run-time errors early
P.8: Don’t leak any resources
P.11: Encapsulate messy constructs, rather than spreading through the code
P.12: Use supporting tools as appropriate
P.13: Use support libraries as appropriate
I.4: Make interfaces precisely and strongly typed
I.11: Never transfer ownership by a raw pointer (T*) or reference (T&)
I.12: Declare a pointer that must not be null as not_null
I.13: Do not pass an array as a single pointer
I.23: Keep the number of function arguments low
F.7: For general use, take T* or T& arguments rather than smart pointers
F.15: Prefer simple and conventional ways of passing information
F.22: Use T* or owner<T*> to designate a single object
F.23: Use a not_null<T> to indicate that “null” is not a valid value
F.25: Use a zstring or a not_null<zstring> to designate a C-style string
F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed
F.27: Use a shared_ptr<T> to share ownership
F.42: Return a T* to indicate a position (only)
F.43: Never (directly or indirectly) return a pointer or a reference to a local object
F.55: Don’t use va_arg arguments
C.31: All resources acquired by a class must be released by the class’s destructor
C.32: If a class has a raw pointer (T*) or reference (T&), consider whether it might be owning
C.33: If a class has an owning pointer member, define a destructor
C.149: Use unique_ptr or shared_ptr to avoid forgetting to delete objects created using new
C.150: Use make_unique() to construct objects owned by unique_ptrs
C.151: Use make_shared() to construct objects owned by shared_ptrs
R.1: Manage resources automatically using resource handles and RAII (Resource Acquisition Is Initialization)
R.2: In interfaces, use raw pointers to denote individual objects (only)
R.3: A raw pointer (a T*) is non-owning
R.5: Prefer scoped objects, don’t heap-allocate unnecessarily
R.10: Avoid malloc() and free()
R.11: Avoid calling new and delete explicitly
R.12: Immediately give the result of an explicit resource allocation to a manager object
R.13: Perform at most one explicit resource allocation in a single expression statement
R.14: Avoid [] parameters, prefer span
R.15: Always overload matched allocation/deallocation pairs
R.20: Use unique_ptr or shared_ptr to represent ownership
R.22: Use make_shared() to make shared_ptrs
R.23: Use make_unique() to make unique_ptrs
ES.20: Always initialize an object
ES.24: Use a unique_ptr<T> to hold pointers
ES.34: Don’t define a (C-style) variadic function
ES.42: Keep use of pointers simple and straightforward
ES.47: Use nullptr rather than 0 or NULL
ES.60: Avoid new and delete outside resource management functions
ES.61: Delete arrays using delete[] and non-arrays using delete
ES.65: Don’t dereference an invalid pointer
E.13: Never throw while being the direct owner of an object
CPL.1: Prefer C++ to C
Gotchas
Usage of smart pointers
This static analyzer causes programmers to use 2 extra characters when using smart pointers: ->
vs (*).
.
smart_pointer->some_function();
|
(*smart_pointer).some_function();
|
the main function and environment variables
A shim module is needed in order to transform main and env functions into a more C++ friendly functions. These have been asked for years.
A Modern C++ Signature for main
Desert Sessions: Improving hostile environment interactions
No unsafe casts
[[static_analysis("no_unsafe_casts")]]
|
no_unsafe_casts is a subset of safer .
|
- Using
C
/core cast produces an error.
- Using
reinterpret_cast
produces an error.
- Using
const_cast
produces an error.
Why?
C
/core cast was replaced by static_cast
and dynamic_cast
.
- The
reinterpret_cast
is needed more for library authors than their users. For library users it usually just causes problems and questions. It is rarely used in daily C++
when coding at a higher level.
- The
const_cast
is needed more for library authors than their users. It is a means for the programmer to lie to oneself. For library users it usually just causes problems and questions. It is rarely used in daily C++
when coding at a higher level.
See the following:
C.146: Use dynamic_cast where class hierarchy navigation is unavoidable
ES.48: Avoid casts
ES.49: If you must use a cast, use a named cast
ES.50: Don’t cast away const
No unions
[[static_analysis("no_union")]]
|
no_union is a subset of safer .
|
Using the union
keyword produces an error. It was replaced by std::variant
, which is safer.
See the following:
C.181: Avoid “naked” unions
No mutable
[[static_analysis("no_mutable")]]
|
no_mutable is a subset of safer .
|
Using the mutable
keyword produces an error. The programmer shall not lie to oneself. The mutable
keyword violates the safety of const
and is rarely used.
No new or delete
[[static_analysis("no_new_delete")]]
|
no_new_delete is a subset of safer .
|
Using the new
and delete
keywords to allocate and deallocate memory produces an error. It was replaced by std::make_unique
and std::make_shared
, which are safer.
See the following:
F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed
F.27: Use a shared_ptr<T> to share ownership
C.149: Use unique_ptr or shared_ptr to avoid forgetting to delete objects created using new
C.150: Use make_unique() to construct objects owned by unique_ptrs
C.151: Use make_shared() to construct objects owned by shared_ptrs
R.11: Avoid calling new and delete explicitly
R.20: Use unique_ptr or shared_ptr to represent ownership
R.22: Use make_shared() to make shared_ptrs
R.23: Use make_unique() to make unique_ptrs
ES.60: Avoid new and delete outside resource management functions
ES.61: Delete arrays using delete[] and non-arrays using delete
No deprecated
[[static_analysis("no_deprecated")]]
|
no_deprecated is a subset of modern .
|
Using anything that has the deprecated attribute on it produces an error.
What may safer
and modern
analyzers be composed of in the future?
No include
[[static_analysis("no_include")]]
|
no_include is a subset of modern .
|
The preprocessor directive #include
has been replaced with import
.
Don’t add the static analyzer until #embed
is added.
No goto
[[static_analysis("no_goto")]]
|
no_goto is a subset of modern .
|
Using the goto
keyword produces an error.
Don’t add until break
and continue
to a label is added. Also a finite state machine library may be needed.
See the following:
Summary
By adding static analysis to the C++
language we can make the language safer and easier to teach because we can restrict how much of the language we use. Human readable errors and references turns the compiler into a teacher freeing human teachers to focus on what the compiler doesn’t handle.
Frequently Asked Questions
Shouldn’t these be warnings instead of errors?
NO, otherwise we’ll be stuck with what we just have. C++
compilers produces plenty of warnings. C++
static analyzers produces plenty of warnings. However, when some one talks about creating a new language, then old language syntax becomes invalid i.e. errors. This is for programmers. Programmers and businesses rarely upgrade their code unless they are forced to. Businesses and Government(s) want errors as well in order to ensure code quality and the assurance that bad code doesn’t exist anywhere in the module. This is also important from a language standpoint because we are essentially pruning; somewhat. Keep in mind though that all of these pruned features still have use now and in the future as more constructs will be built upon them which is why they need to be part of the language just not a part of everyday usage of the language.
Why at the module level? Why not safe and unsafe blocks?
Programmers and businesses rarely upgrade their code unless they are forced to. New programmers need training wheels and some of us older programmers like them too. Due to the proliferation of government regulations and oversight, businesses have acquired software composition analysis
services and tools. These services map security errors to specific versions of modules; specifically programming artifacts such as executables and libraries. As such, businesses want to know is a module reasonably safe.
You must really hate pointers?
Actually, I love C
, C++
and pointers.
- I recognize that most of the time, when I code, that I don’t need them.
- I recognize that past fundamental
C++
libraries use pointers but the users of those libraries don’t need them.
- I recognize that present fundamental libraries such
function_ref
uses void*
for type erasure but the users of function_ref
, most of the time, won’t need it.
- I recognize that future fundamental libraries such as dynamic polymorphic traits also need pointers for type erasure but they don’t expect their users to fidget with raw pointers.
- I also recognize that 1 programmer writes a library but hundreds use the library without needing the same parts of C++ used in its creation.
- Pointers are simple and easy for memory mapped hardware but many C++ programmers don’t operate at this level.
- A few will create an OS [driver] but thousands will use it.
The fact is pointers, unsafe casts, union
, mutable
and goto
are the engine of C++ change. As such it would be foolish to remove them but it is also unrealistic for users/drivers of a vehicle to have to drive with nothing between them and the engine without listening to them clamor for interior finishing.
C++ can’t standardize specific static analyzers
- Can’t
C++
provide the static_analysis
attribute so that static analyzers can be called?
- Can’t
C++
reserve unscoped or names that start with std.
, c++.
, cpp.
, cxx.
or c.
are for future standardization?
- Can’t
C++
reserve the names of static analyzers in the reserved C++
static analyzer namespace?
- Can’t
C++
recommend these reserved static analyzers and leave it to the compiler writers to appease their users that clamor for them?
References
Jarrad J. Waterloo <descender76 at gmail dot com>
C++ is the next C++
Table of contents
Abstract
Programmer’s, Businesses and Government(s) want C++ to be safer and simpler. This has led some
C++
programmers to create new programming languages or preprocessors which again is a new language. This paper discusses using static analysis to make theC++
language itself safer and simpler.Motivating Examples
Following is a wishlist. Most are optional. While, they all would be of benefit. It all starts with a new repeatable module level attribute that would preferably be applied once in the
primary module interface unit
and would automatically apply to it and allmodule implementation unit
(s). It could also be applied to amodule implementation unit
but that would generally be less useful. However, it might aid in gradual migration.static_analysis
attribute could be passed as either an environment variable and/or command line argument to compilers so it could be used by pipelines to assert the degree of conformance to the defined static analyzer without actually changing the source.The name of the static analyzer are dotted. Unscoped or names that start with
std.
,c++.
,cpp.
,cxx.
orc.
are reserved for standardization.This proposal wants to stardardize two overarching static analyzer names;
safer
andmodern
.The
safer
analyzer is for safety, primarily memory related. It is for those businesses and programmers who must conform to safety standards.The
safer
analyzer is a subset ofmodern
analyzer. Themodern
analyzer goes beyond just memory and safety concerns. It can be thought of as bleeding edge. It is for those businesses and programmers who commit to safety and higher quality modern code.Neither is concerned about formatting or nitpicking. Both static analyzers only produce errors. They both represent +∞. These are meant for programmers, businesses and governments in which safety takes precedence. When a new version of the standard is released and adds new sub static analyzers than everyone’s code is broken until their code is fixed. These sub static analyzers usually consist of features that have been mostly replaced with some other feature. It would be ideal if the errors produced not only say that the code is wrong but also provide a link to html page(s) maintained by both the
C++
teaching group, the authors of theC++ Core Guidelines
[1] and compiler specific errors. These pages should provide example(s) of what is being replaced and by what was it replaced. Mentioning the version of theC++
standard would also be helpful.All modules can be used even if they don’t use the
static_analysis
attribute as this allows gradual adoption.What are the
safer
andmodern
analyzers composed of?These overarching static analyzers are composed of multiple static analyzers which can be used individually to allow a degree of gradual adoption.
Use lvalue references
use_lvalue_references
is a subset ofsafer
.const
character type” or “const
pointer toconst
character type” and their arguments were string literals.std::string
andstd::string_view
must be creatable at compile timeWHY?
C++
has been advocated to programmers in other programming languages who complain about memory issues. This allows us to show them what we have been saying for decades.lvalue references
1985: Cfront 1.0 [2]
STL
1992 [2:1]
std::unique_ptr
,std::shared_ptr
,std::weak_ptr
,std::reference_wrapper
,std::make_shared
C++11
std::make_unique
C++14
std::string_view
,std::optional
,std::any
,std::variant
C++17
std::make_shared
support arrays,std::span
C++20
The
C++ Core Guidelines
[1:1] identifies issues that this feature helps to mitigate.P.4: Ideally, a program should be statically type safe
[3]P.6: What cannot be checked at compile time should be checkable at run time
[4]P.7: Catch run-time errors early
[5]P.8: Don’t leak any resources
[6]P.11: Encapsulate messy constructs, rather than spreading through the code
[7]P.12: Use supporting tools as appropriate
[8]P.13: Use support libraries as appropriate
[9]I.4: Make interfaces precisely and strongly typed
[10]I.11: Never transfer ownership by a raw pointer (T*) or reference (T&)
[11]I.12: Declare a pointer that must not be null as not_null
[12]I.13: Do not pass an array as a single pointer
[13]I.23: Keep the number of function arguments low
[14]F.7: For general use, take T* or T& arguments rather than smart pointers
[15]F.15: Prefer simple and conventional ways of passing information
[16]F.22: Use T* or owner<T*> to designate a single object
[17]F.23: Use a not_null<T> to indicate that “null” is not a valid value
[18]F.25: Use a zstring or a not_null<zstring> to designate a C-style string
[19]F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed
[20]F.27: Use a shared_ptr<T> to share ownership
[21]F.42: Return a T* to indicate a position (only)
[22]F.43: Never (directly or indirectly) return a pointer or a reference to a local object
[23]F.55: Don’t use va_arg arguments
[24]C.31: All resources acquired by a class must be released by the class’s destructor
[25]C.32: If a class has a raw pointer (T*) or reference (T&), consider whether it might be owning
[26]C.33: If a class has an owning pointer member, define a destructor
[27]C.149: Use unique_ptr or shared_ptr to avoid forgetting to delete objects created using new
[28]C.150: Use make_unique() to construct objects owned by unique_ptrs
[29]C.151: Use make_shared() to construct objects owned by shared_ptrs
[30]R.1: Manage resources automatically using resource handles and RAII (Resource Acquisition Is Initialization)
[31]R.2: In interfaces, use raw pointers to denote individual objects (only)
[32]R.3: A raw pointer (a T*) is non-owning
[33]R.5: Prefer scoped objects, don’t heap-allocate unnecessarily
[34]R.10: Avoid malloc() and free()
[35]R.11: Avoid calling new and delete explicitly
[36]R.12: Immediately give the result of an explicit resource allocation to a manager object
[37]R.13: Perform at most one explicit resource allocation in a single expression statement
[38]R.14: Avoid [] parameters, prefer span
[39]R.15: Always overload matched allocation/deallocation pairs
[40]R.20: Use unique_ptr or shared_ptr to represent ownership
[41]R.22: Use make_shared() to make shared_ptrs
[42]R.23: Use make_unique() to make unique_ptrs
[43]ES.20: Always initialize an object
[44]ES.24: Use a unique_ptr<T> to hold pointers
[45]ES.34: Don’t define a (C-style) variadic function
[46]ES.42: Keep use of pointers simple and straightforward
[47]ES.47: Use nullptr rather than 0 or NULL
[48]ES.60: Avoid new and delete outside resource management functions
[49]ES.61: Delete arrays using delete[] and non-arrays using delete
[50]ES.65: Don’t dereference an invalid pointer
[51]E.13: Never throw while being the direct owner of an object
[52]CPL.1: Prefer C++ to C
[53]Gotchas
Usage of smart pointers
This static analyzer causes programmers to use 2 extra characters when using smart pointers:
->
vs(*).
.the main function and environment variables
A shim module is needed in order to transform main and env functions into a more C++ friendly functions. These have been asked for years.
A Modern C++ Signature for main
[54]Desert Sessions: Improving hostile environment interactions
[55]No unsafe casts
no_unsafe_casts
is a subset ofsafer
.C
/core cast produces an error.reinterpret_cast
produces an error.const_cast
produces an error.Why?
C
/core cast was replaced bystatic_cast
anddynamic_cast
.reinterpret_cast
is needed more for library authors than their users. For library users it usually just causes problems and questions. It is rarely used in dailyC++
when coding at a higher level.const_cast
is needed more for library authors than their users. It is a means for the programmer to lie to oneself. For library users it usually just causes problems and questions. It is rarely used in dailyC++
when coding at a higher level.See the following:
C.146: Use dynamic_cast where class hierarchy navigation is unavoidable
[56]ES.48: Avoid casts
[57]ES.49: If you must use a cast, use a named cast
[58]ES.50: Don’t cast away const
[59]No unions
no_union
is a subset ofsafer
.Using the
union
keyword produces an error. It was replaced bystd::variant
, which is safer.See the following:
C.181: Avoid “naked” unions
[60]No mutable
no_mutable
is a subset ofsafer
.Using the
mutable
keyword produces an error. The programmer shall not lie to oneself. Themutable
keyword violates the safety ofconst
and is rarely used.No new or delete
no_new_delete
is a subset ofsafer
.Using the
new
anddelete
keywords to allocate and deallocate memory produces an error. It was replaced bystd::make_unique
andstd::make_shared
, which are safer.See the following:
F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed
[20:1]F.27: Use a shared_ptr<T> to share ownership
[21:1]C.149: Use unique_ptr or shared_ptr to avoid forgetting to delete objects created using new
[28:1]C.150: Use make_unique() to construct objects owned by unique_ptrs
[29:1]C.151: Use make_shared() to construct objects owned by shared_ptrs
[30:1]R.11: Avoid calling new and delete explicitly
[36:1]R.20: Use unique_ptr or shared_ptr to represent ownership
[41:1]R.22: Use make_shared() to make shared_ptrs
[42:1]R.23: Use make_unique() to make unique_ptrs
[43:1]ES.60: Avoid new and delete outside resource management functions
[49:1]ES.61: Delete arrays using delete[] and non-arrays using delete
[50:1]No deprecated
no_deprecated
is a subset ofmodern
.Using anything that has the deprecated attribute on it produces an error.
What may
safer
andmodern
analyzers be composed of in the future?No include
no_include
is a subset ofmodern
.The preprocessor directive
#include
has been replaced withimport
.Don’t add the static analyzer until
#embed
is added.No goto
no_goto
is a subset ofmodern
.Using the
goto
keyword produces an error.Don’t add until
break
andcontinue
to a label is added. Also a finite state machine library may be needed.See the following:
ES.76: Avoid goto
[61]Summary
By adding static analysis to the
C++
language we can make the language safer and easier to teach because we can restrict how much of the language we use. Human readable errors and references turns the compiler into a teacher freeing human teachers to focus on what the compiler doesn’t handle.Frequently Asked Questions
Shouldn’t these be warnings instead of errors?
NO, otherwise we’ll be stuck with what we just have.
C++
compilers produces plenty of warnings.C++
static analyzers produces plenty of warnings. However, when some one talks about creating a new language, then old language syntax becomes invalid i.e. errors. This is for programmers. Programmers and businesses rarely upgrade their code unless they are forced to. Businesses and Government(s) want errors as well in order to ensure code quality and the assurance that bad code doesn’t exist anywhere in the module. This is also important from a language standpoint because we are essentially pruning; somewhat. Keep in mind though that all of these pruned features still have use now and in the future as more constructs will be built upon them which is why they need to be part of the language just not a part of everyday usage of the language.Why at the module level? Why not safe and unsafe blocks?
Programmers and businesses rarely upgrade their code unless they are forced to. New programmers need training wheels and some of us older programmers like them too. Due to the proliferation of government regulations and oversight, businesses have acquired
software composition analysis
services and tools. These services map security errors to specific versions of modules; specifically programming artifacts such as executables and libraries. As such, businesses want to know is a module reasonably safe.You must really hate pointers?
Actually, I love
C
,C++
and pointers.C++
libraries use pointers but the users of those libraries don’t need them.function_ref
usesvoid*
for type erasure but the users offunction_ref
, most of the time, won’t need it.The fact is pointers, unsafe casts,
union
,mutable
andgoto
are the engine of C++ change. As such it would be foolish to remove them but it is also unrealistic for users/drivers of a vehicle to have to drive with nothing between them and the engine without listening to them clamor for interior finishing.C++ can’t standardize specific static analyzers
C++
provide thestatic_analysis
attribute so that static analyzers can be called?C++
reserve unscoped or names that start withstd.
,c++.
,cpp.
,cxx.
orc.
are for future standardization?C++
reserve the names of static analyzers in the reservedC++
static analyzer namespace?C++
recommend these reserved static analyzers and leave it to the compiler writers to appease their users that clamor for them?References
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines ↩︎ ↩︎
https://en.cppreference.com/w/cpp/language/history ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#p4-ideally-a-program-should-be-statically-type-safe ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#p6-what-cannot-be-checked-at-compile-time-should-be-checkable-at-run-time ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#p7-catch-run-time-errors-early ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#p8-dont-leak-any-resources ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#p11-encapsulate-messy-constructs-rather-than-spreading-through-the-code ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#p12-use-supporting-tools-as-appropriate ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#p13-use-support-libraries-as-appropriate ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i4-make-interfaces-precisely-and-strongly-typed ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i11-never-transfer-ownership-by-a-raw-pointer-t-or-reference-t ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i12-declare-a-pointer-that-must-not-be-null-as-not_null ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i13-do-not-pass-an-array-as-a-single-pointer ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i23-keep-the-number-of-function-arguments-low ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f7-for-general-use-take-t-or-t-arguments-rather-than-smart-pointers ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f15-prefer-simple-and-conventional-ways-of-passing-information ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f22-use-t-or-ownert-to-designate-a-single-object ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f23-use-a-not_nullt-to-indicate-that-null-is-not-a-valid-value ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f25-use-a-zstring-or-a-not_nullzstring-to-designate-a-c-style-string ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f26-use-a-unique_ptrt-to-transfer-ownership-where-a-pointer-is-needed ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f27-use-a-shared_ptrt-to-share-ownership ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f42-return-a-t-to-indicate-a-position-only ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f43-never-directly-or-indirectly-return-a-pointer-or-a-reference-to-a-local-object ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f55-dont-use-va_arg-arguments ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c31-all-resources-acquired-by-a-class-must-be-released-by-the-classs-destructor ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c32-if-a-class-has-a-raw-pointer-t-or-reference-t-consider-whether-it-might-be-owning ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c33-if-a-class-has-an-owning-pointer-member-define-a-destructor ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c149-use-unique_ptr-or-shared_ptr-to-avoid-forgetting-to-delete-objects-created-using-new ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c150-use-make_unique-to-construct-objects-owned-by-unique_ptrs ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c151-use-make_shared-to-construct-objects-owned-by-shared_ptrs ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r1-manage-resources-automatically-using-resource-handles-and-raii-resource-acquisition-is-initialization ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r2-in-interfaces-use-raw-pointers-to-denote-individual-objects-only ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r3-a-raw-pointer-a-t-is-non-owning ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r5-prefer-scoped-objects-dont-heap-allocate-unnecessarily ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r10-avoid-malloc-and-free ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r11-avoid-calling-new-and-delete-explicitly ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r12-immediately-give-the-result-of-an-explicit-resource-allocation-to-a-manager-object ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r13-perform-at-most-one-explicit-resource-allocation-in-a-single-expression-statement ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r14-avoid--parameters-prefer-span ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r15-always-overload-matched-allocationdeallocation-pairs ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r20-use-unique_ptr-or-shared_ptr-to-represent-ownership ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r22-use-make_shared-to-make-shared_ptrs ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r23-use-make_unique-to-make-unique_ptrs ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es20-always-initialize-an-object ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es24-use-a-unique_ptrt-to-hold-pointers ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#-es34-dont-define-a-c-style-variadic-function ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es42-keep-use-of-pointers-simple-and-straightforward ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es47-use-nullptr-rather-than-0-or-null ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es60-avoid-new-and-delete-outside-resource-management-functions ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es61-delete-arrays-using-delete-and-non-arrays-using-delete ↩︎ ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es65-dont-dereference-an-invalid-pointer ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#e13-never-throw-while-being-the-direct-owner-of-an-object ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#cpl1-prefer-c-to-c ↩︎
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0781r0.html ↩︎
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1275r0.html ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c146-use-dynamic_cast-where-class-hierarchy-navigation-is-unavoidable ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es48-avoid-casts ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es49-if-you-must-use-a-cast-use-a-named-cast ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es50-dont-cast-away-const ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c181-avoid-naked-unions ↩︎
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es76-avoid-goto ↩︎