当前位置:网站首页>本周小贴士#134:make_unique与私有构造函数
本周小贴士#134:make_unique与私有构造函数
2022-07-07 15:39:00 【-飞鹤-】
作为totw#134最初发表于2017年5月10日
由谷歌工程师Yitzhak Mandelbaum创作
因此,你阅读了小贴士#126并准备留下一些新的东西。一切都是正常的,直到你尝试使用absl::make_unique并使用私有构造函数去构造对象,但是编译失败。让我们看一下这个问题的一个具体示例,以便理解哪里出了问题。然后,我们可以讨论一些解决方案。
示例:制造小部件
你正在定义一个类来展示小部件。每个小部件都有一个标识符,这些标识符受某些约束。为了确保一直满足这些约束,你将Widget类的构造函数声明为私有,并为用户提供工厂函数Make,用于生成具有合适标识符的小部件。(有关为什么工厂函数优于初始化方法的建议,请参阅技巧 #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_;
}
当你尝试编译时,你将得到如下的错误:
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) {
}
当make已经访问私有构造函数时,absl::make_unique无法工作!注意,这个问题也出现在友元下。例如:Widget的友元使用absl::make_unique去构造Widget会有同样的问题。
建议
我们推荐以下的任一个替代方案:
- 使用new和absl::WrapUnique,但请解释你的选择。例如:Widget的友元使用absl
// 使用new访问非仅有构造函数 return absl::WrapUnique(new Widget(...));
- 考虑构造函数是否可以安全地公开。如果是这样,那么在适合直接构造时将其公开并记录。
在很多情况下,将构造函数标记为私有是过度设计。在这些情况下,最好的解决方案是将你的构造函数标记为公有并记录它们的正确使用。然而,如果你的构造函数需要设置为私有(比如说,为了确保类不变量),则使用new和WrapUnique。
为什么我不能友元absl::make_unique?
你可能想友元absl::make_unique,这样它就可以访问你的私有构造函数。这是一个糟糕的主意,有几个原因:
首先,虽然对友元实践的全面讨论超过出本贴士的范围,但是一个好的经验法则是“不要远距离的朋友关系”。否则,你将创建一个友元竞争声明,一个不由所有者维护的声明。另外请参见风格指南建议。
其次,请注意,你依赖于absl::make_unique的实现细节,即它直接调用new。如果它被重构以间接调用new——例如,在构造C++14或更高版本中,absl::make_unique是std::make_unique的别名,并且友元声明是无效的。
最后,通过友元absl::make_unique,你允许任何人以这种方式创建对象,那么为什么不将你的构造函数声明为公有,然后完全避免这个问题呢?
std::shared_ptr呢?
对于std::shared_ptr,情况有些不同。此处没有absl::WrapSahred和模拟(std::shared_ptr(new T(…)))涉及两个分配,其中std::make_shared可以用一个来完成。如果这种差异很重要,那么请考虑习惯用法:让构造函数采用只有特定代码才能创建的特殊标记。例如:
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_;
};
关于习惯用法,参考以下文章:
More Useful Empty Classes
Passkey Idiom and Better Friendship in C++
边栏推荐
- 管理VDI的几个最佳实践
- [Seaborn] combination chart: pairplot and jointplot
- Reflections on "product managers must read: five classic innovative thinking models"
- Biped robot controlled by Arduino
- Problems encountered in Jenkins' release of H5 developed by uniapp
- 第二十四届中国科协湖南组委会调研课题组一行莅临麒麟信安调研考察
- LeetCode 535(C#)
- QT picture background color pixel processing method
- 麒麟信安加入宁夏商用密码协会
- LeetCode 1654. The minimum number of jumps to get home one question per day
猜你喜欢
【Seaborn】组合图表:FacetGrid、JointGrid、PairGrid
[image sensor] correlated double sampling CDs
麒麟信安携异构融合云金融信创解决方案亮相第十五届湖南地区金融科技交流会
LeetCode刷题day49
Sator launched Web3 game "satorspace" and launched hoobi
【TPM2.0原理及应用指南】 12、13、14章
Process from creation to encapsulation of custom controls in QT to toolbar (I): creation of custom controls
Shallow understanding Net core routing
What is cloud computing?
麒麟信安中标国网新一代调度项目!
随机推荐
MySQL implements the query of merging two fields into one field
Skimage learning (2) -- RGB to grayscale, RGB to HSV, histogram matching
跟奥巴马一起画方块(Lua)
LeetCode 1043. Separate the array to get the maximum and daily questions
Skimage learning (3) -- adapt the gray filter to RGB images, separate colors by immunohistochemical staining, and filter the maximum value of the region
Flash build API service
On Apache Doris Fe processing query SQL source code analysis
L1-023 输出GPLT(Lua)
SlashData开发者工具榜首等你而定!!!
How to mount the original data disk without damage after the reinstallation of proxmox ve?
【饭谈】如何设计好一款测试平台?
Pychart ide Download
LeetCode 1696. Jumping game VI daily question
Share the latest high-frequency Android interview questions, and take you to explore the Android event distribution mechanism
NeRF:DeepFake的最终替代者?
测试用例管理工具推荐
[video / audio data processing] Shanghai daoning brings you elecard download, trial and tutorial
无法链接远程redis服务器(解决办法百分百)
LeetCode 213. Home raiding II daily question
LeetCode 1654. The minimum number of jumps to get home one question per day