当前位置:网站首页>Tips for this week 134: make_ Unique and private constructors
Tips for this week 134: make_ Unique and private constructors
2022-07-07 17:57:00 【-Flying crane-】
As totw#134 Originally published in 2017 year 5 month 10 Japan
By Google engineers Yitzhak Mandelbaum A literary creation
therefore , You read the tips #126 And prepare to leave something new . Everything is normal , Until you try to use absl::make_unique And use private constructors to construct objects , But the compilation failed . Let's take a look at a specific example of this problem , In order to understand what went wrong . then , We can discuss some solutions .
Example : Manufacturing widgets
You are defining a class to display widgets . Each widget has an identifier , These identifiers are subject to certain constraints . To ensure that these constraints are always met , You will be Widget The constructor of the class is declared private , And provide factory functions for users Make, Used to generate widgets with appropriate identifiers .( Suggestions on why factory functions are better than initialization methods , See Tips #42.)
class Widget {
public:
static std::unique_ptr<Widget> Make() {
return absl::make_unique<Widget>(GenerateId());
}
private:
Widget(int id) : id_(id) {
}
static int GenerateId();
int id_;
}
When you try to compile , You will get the following error :
error: calling a private constructor of class 'Widget'
{
return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
^
note: in instantiation of function template specialization
'absl::make_unique<Widget, int>' requested here
return absl::make_unique<Widget>(GenerateId());
^
note: declared private here
Widget(int id) : id_(id) {
}
When make When the private constructor has been accessed ,absl::make_unique Unable to work ! Be careful , This problem also appears under friends . for example :Widget Friends use absl::make_unique To construct Widget There will be the same problem .
Suggest
We recommend any of the following alternatives :
- Use new and absl::WrapUnique, But please explain your choice . for example :Widget Friends use absl
// Use new Access non constructor only return absl::WrapUnique(new Widget(...));
- Consider whether constructors can be safely exposed . If so , Then expose and record it when it is suitable for direct construction .
In many cases , Marking constructors private is overdesign . In these cases , The best solution is to mark your constructors public and record their correct use . However , If your constructor needs to be private ( for instance , To ensure class invariants ), Then use new and WrapUnique.
Why can't I friend absl::make_unique?
You may want to be friends absl::make_unique, So it can access your private constructor . It's a bad idea , There are several reasons :
First , Although a comprehensive discussion of friend practice is beyond the scope of this tip , But a good rule of thumb is “ Don't be a long-distance friend ”. otherwise , You will create a friend competition statement , A statement that is not maintained by the owner . See also style guide recommendations .
secondly , Please note that , You rely on absl::make_unique Implementation details , That is, it directly calls new. If it is refactored to call indirectly new—— for example , In the structure C++14 Or later ,absl::make_unique yes std::make_unique Another name for , And the friend declaration is invalid .
Last , Through friends absl::make_unique, You allow anyone to create objects in this way , So why not declare your constructor public , Then completely avoid this problem ?
std::shared_ptr Well ?
about std::shared_ptr, It's a little different . There is no absl::WrapSahred And simulation (std::shared_ptr(new T(…))) There are two distributions involved , among std::make_shared You can use one to complete . If this difference is important , Then consider idioms : Let the constructor take special tags that only specific code can create . for example :
class Widget {
class Token {
private:
Token() {
}
friend Widget;
};
public:
static std::shared_ptr<Widget> Make() {
return std::make_shared<Widget>(Token{
}, GenerateId());
}
Widget(Token, int id) : id_(id) {
}
private:
static int GenerateId();
int id_;
};
About idioms , Refer to the following article :
More Useful Empty Classes
Passkey Idiom and Better Friendship in C++
边栏推荐
- 【4500字归纳总结】一名软件测试工程师需要掌握的技能大全
- [OKR target management] value analysis
- Dateticket and timeticket, functions and usage of date and time selectors
- Ansible learning summary (9) -- ansible loop, condition judgment, trigger, processing failure and other task control use summary
- 【可信计算】第十二次课:TPM授权与会话
- 第3章业务功能开发(安全退出)
- Sanxian Guidong JS game source code
- MySQL index hit level analysis
- Cartoon | who is the first ide in the universe?
- Self made dataset in pytoch for dataset rewriting
猜你喜欢
Function and usage of textswitch text switcher
alertDialog創建对话框
Mui side navigation anchor positioning JS special effect
Functions and usage of tabhost tab
Supplementary instructions to relevant rules of online competition
Mobile pixel bird game JS play code
[OKR target management] case analysis
viewflipper的功能和用法
Function and usage of numberpick
【4500字归纳总结】一名软件测试工程师需要掌握的技能大全
随机推荐
漫画 | 宇宙第一 IDE 到底是谁?
Import requirements in batches during Yolo training Txt
【可信计算】第十二次课:TPM授权与会话
Mui side navigation anchor positioning JS special effect
企业经营12法的领悟
Please insert the disk into "U disk (H)" & unable to access the disk structure is damaged and cannot be read
目标管理【管理学之十四】
Toast will display a simple prompt message on the program interface
Cartoon | who is the first ide in the universe?
Vscode three configuration files about C language
使用OneDNS完美解决办公网络优化问题
Deep learning - make your own dataset
在窗口上面显示进度条
本周小贴士#141:注意隐式转换到bool
如何在软件研发阶段落地安全实践
Function and usage of calendar view component
Management by objectives [14 of management]
Numberpick的功能和用法
Notification is the notification displayed in the status bar of the phone
actionBar 导航栏学习