当前位置:网站首页>本周小贴士#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++
边栏推荐
- 【Seaborn】组合图表:FacetGrid、JointGrid、PairGrid
- 【信息安全法律法規】複習篇
- The process of creating custom controls in QT to encapsulating them into toolbars (II): encapsulating custom controls into toolbars
- [video / audio data processing] Shanghai daoning brings you elecard download, trial and tutorial
- Flask build API service SQL configuration file
- 如何在软件研发阶段落地安全实践
- LeetCode 120. Triangle minimum path and daily question
- 【饭谈】那些看似为公司着想,实际却很自私的故事 (一:造轮子)
- Sator推出Web3遊戲“Satorspace” ,並上線Huobi
- Skimage learning (3) -- adapt the gray filter to RGB images, separate colors by immunohistochemical staining, and filter the maximum value of the region
猜你喜欢
【信息安全法律法规】复习篇
状态模式 - Unity(有限状态机)
How to choose the appropriate automated testing tools?
企业即时通讯软件是什么?它有哪些优势呢?
How to add aplayer music player in blog
【TPM2.0原理及应用指南】 5、7、8章
QML beginner
Siggraph 2022 best technical paper award comes out! Chen Baoquan team of Peking University was nominated for honorary nomination
麒麟信安中标国网新一代调度项目!
With the latest Alibaba P7 technology system, mom doesn't have to worry about me looking for a job anymore
随机推荐
99%的人都不知道|私有化部署还永久免费的即时通讯软件!
The server is completely broken and cannot be repaired. How to use backup to restore it into a virtual machine without damage?
How to mount the original data disk without damage after the reinstallation of proxmox ve?
Sator launched Web3 game "satorspace" and launched hoobi
LeetCode 1155. N ways to roll dice one question per day
Solidity函数学习
Is AI more fair than people in the distribution of wealth? Research on multiplayer game from deepmind
LeetCode 515(C#)
LeetCode 403. Frog crossing the river daily
LeetCode 1774. The dessert cost closest to the target price is one question per day
Number of exchanges in the 9th Blue Bridge Cup finals
With the latest Alibaba P7 technology system, mom doesn't have to worry about me looking for a job anymore
Process from creation to encapsulation of custom controls in QT to toolbar (I): creation of custom controls
LeetCode 648(C#)
Sator a lancé le jeu web 3 "satorspace" et a lancé huobi
字符串 - string(Lua)
麒麟信安中标国网新一代调度项目!
99% 用户在 Power BI 云端报表常犯错误
麒麟信安云平台全新升级!
【饭谈】如何设计好一款测试平台?