当前位置:网站首页>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++
边栏推荐
猜你喜欢
【深度学习】3分钟入门
第2章搭建CRM项目开发环境(数据库设计)
什么是敏捷测试
【4500字归纳总结】一名软件测试工程师需要掌握的技能大全
Run Yolo v5-5.0 and report an error. If the sppf error cannot be found, solve it
Slider plug-in for swiper left and right switching
Interviewer: why is the page too laggy and how to solve it? [test interview question sharing]
【OKR目标管理】案例分析
机器视觉(1)——概述
深入浅出图解CNN-卷积神经网络
随机推荐
第2章搭建CRM项目开发环境(搭建开发环境)
【信息安全法律法規】複習篇
Show progress bar above window
List selection JS effect with animation
使用 xml资源文件定义菜单
What is agile testing
[answer] if the app is in the foreground, the activity will not be recycled?
alertDialog創建对话框
Please insert the disk into "U disk (H)" & unable to access the disk structure is damaged and cannot be read
TabHOST 选项卡的功能和用法
使用OneDNS完美解决办公网络优化问题
MySQL index hit level analysis
手机app外卖订餐个人中心页面
数字化转型的主要工作
本周小贴士#141:注意隐式转换到bool
Deep learning - make your own dataset
Mrs offline data analysis: process OBS data through Flink job
第1章CRM核心业务介绍
机器视觉(1)——概述
Functions and usage of viewswitch