如何防止其他人在堆栈上创建您的类的新实例?
Posted
技术标签:
【中文标题】如何防止其他人在堆栈上创建您的类的新实例?【英文标题】:How to prevent others create a new instance of your class on stack ? 【发布时间】:2011-12-16 04:00:45 【问题描述】:假设你编写了一个类 A,构造函数是私有的(以防止其他人在堆栈上创建它),然后有一天另一个开发人员添加了一个新的 ctor,比如 A(int),并想在 main() 中使用:
一一(1)
在堆栈上创建它。你如何防止这种情况发生?
我的解决方案:
声明一个公共构造函数
A(void& input )
Cerr << “please do not create it on stack” << endl ;
exit(1);
我不确定它是否正确?
谢谢
【问题讨论】:
请问为什么你想防止这种情况发生?给我们一个令人信服的理由,我们可能会在此基础上为您提供更好的实施。 @BenjaminLindley C++ 如此复杂的原因之一是为人们提供尽可能多的工具来在编译时执行代码库的规则。它们都不会是完美的……您可以争辩说不应该打扰const
,因为可以编辑您的代码的人可以将const_cast
删除,但是 const-correctness 无论如何都会捕获很多错误。想要使用书中的每一个技巧来帮助执行代码库的实践和协议并减少错误并没有什么“愚蠢”的。对于这种情况,甚至可以这样做……看我的回答。
@HostileFork:除了在C++中,只要你可以构造一个对象,你就可以随时构造它。 A a;
和 std::unique_ptr<A> a;
之间的最大区别是什么?我完全支持编译器强制执行,您提出的解决方案很有趣,而且不太打扰,但在这种情况下,它真的不起作用。
@MatthieuM。好吧,我们再次使用油漆:-/ 是的,如果您只是从工厂方法返回一个指针,则没有太大区别,但是如果您返回一个 shared_ptr(例如),那么这种事情可能会影响不同。
【参考方案1】:
显然,您无法阻止它。如果其他人可以直接编辑您的代码,那么他们可以为所欲为。
【讨论】:
当然你在一般意义上是对的......但是这个 FGITW 答案有多大帮助,真的吗?请参阅我对问题的评论以及我的回答。【参考方案2】:在评论中写下这样的话:
class A
private:
// This is private on purpose to prevent allocation on the stack.
// We'll fire you if you ever write a new constructor that isn't private.
A();
;
这个评论是开玩笑的(大部分),但它指向一个重要的概念。诸如不允许堆栈分配之类的代码约定需要通过同行评审来强制执行。正如其他人所说,理论上其他人可以随心所欲地更改代码。但是一个好的同行评审过程将有助于控制这一点。恕我直言,这比新员工可能不一定了解的一些聪明的编译器技巧更具成本效益。
【讨论】:
确实如此,尤其是任何可以添加公共构造函数的人显然都可以修改类的任何部分,包括为防止在堆栈上分配而实施的任何机制。【参考方案3】:我认为您想要的解决方案是以下步骤。
-
为构造函数提供“私有”访问权限。
制作一个非成员静态函数,通过new或malloc创建实例并返回。
使用该函数创建类的实例。
我相信这些步骤可能会解决您的问题。
【讨论】:
【参考方案4】:正如其他人所说,你不能阻止可以编辑你的课程的人让它做几乎任何事情......但是......
...如果您想要一个比注释更易于编译的方法,您可以从没有默认构造函数的类继承。任何编写构造函数的人都会(希望)注意到它。你可以让它的名字提示人们采取某些预防措施。
类似这样的:
class DoNotStackConstruct
protected:
DoNotStackConstruct(const char* dummy)
;
class A : protected DoNotStackConstruct
private:
A () : DoNotStackConstruct ("PLEASE make all A constructors private!")
// your code here
public:
static std::tr1::shared_ptr<A> newA()
return std::tr1::shared_ptr<A>(new A);
/* ... a bunch of code ... */
/* ... then someone later adds the following ... */
public:
A (int i)
// can't force them to make it private, but...
// this won't compile without mentioning DoNotStackConstruct
;
一旦你开始使用 C++11,就会有“委托构造函数”,而这个技巧会少一些:
Can I call a constructor from another constructor (do constructor chaining) in C++?
然后他们将能够委托给A()
,而无需访问源代码行并复制“嘿,不要公开你的构造函数!”文本。但默认情况下,他们在第一次尝试时仍然会收到编译器错误。
【讨论】:
deleteA
方法完全没必要,构造函数是private
,不是析构函数。
@MatthieuM。最初我让它返回一个 shared_ptr (这是我打扰私有构造函数的唯一原因),但我只是将它配对以进一步“简化”。不过你是对的,所以我会砍掉它......很难决定在填写示例时使用多少“绘画”,也很难决定何时真正费心编译它:-/以上是关于如何防止其他人在堆栈上创建您的类的新实例?的主要内容,如果未能解决你的问题,请参考以下文章