当前位置:网站首页>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++
边栏推荐
- datepicket和timepicket,日期、时间选择器的功能和用法
- 《世界粮食安全和营养状况》报告发布:2021年全球饥饿人口增至8.28亿
- Enum + Validation 的个人最佳实践 demo 分享
- 带动画的列表选中js特效
- Ansible learning summary (9) -- ansible loop, condition judgment, trigger, processing failure and other task control use summary
- js拉下帷幕js特效显示层
- 手机版像素小鸟游js戏代码
- actionBar 导航栏学习
- 三仙归洞js小游戏源码
- Robot engineering lifelong learning and work plan-2022-
猜你喜欢
Simple loading animation
Vscode three configuration files about C language
手机版像素小鸟游js戏代码
toast会在程序界面上显示一个简单的提示信息
【重新理解通信模型】Reactor 模式在 Redis 和 Kafka 中的应用
Functions and usage of serachview
mui侧边导航锚点定位js特效
Pytorch中自制数据集进行Dataset重写
Target detection 1 -- actual operation of Yolo data annotation and script for converting XML to TXT file
【OKR目标管理】价值分析
随机推荐
Simple loading animation
阿富汗临时政府安全部队对极端组织“伊斯兰国”一处藏匿点展开军事行动
ICer知识点杂烩(后附大量题目,持续更新中)
DatePickerDialog和trimepickerDialog
测试3个月,成功入职 “字节”,我的面试心得总结
MRS离线数据分析:通过Flink作业处理OBS数据
Numberpick的功能和用法
zdog.js火箭转向动画js特效
手机版像素小鸟游js戏代码
actionBar 导航栏学习
Notification is the notification displayed in the status bar of the phone
【可信计算】第十次课:TPM密码资源管理(二)
仿今日头条APP顶部点击可居中导航
Native JS verification code
Functions and usage of ratingbar
Ansible learning summary (9) -- ansible loop, condition judgment, trigger, processing failure and other task control use summary
Dateticket and timeticket, functions and usage of date and time selectors
Management by objectives [14 of management]
cf:C. Factorials and Powers of Two【dp + 排序 + 选不选板子 + 选若干个数等于已知和的最少数】
[tpm2.0 principle and Application guide] Chapter 1-3