【发布时间】:2011-04-05 13:53:44
【问题描述】:
我现在正在反对以下提议,我想知道反对或支持它的法律和道德论据。
我们有什么:
#include <vector>
class T;
class C
{
public:
C() { }
~C( ) { /*something non-trivial: say, calls delete for all elements in v*/ }
// a lot of member functions that modify C
// a lot of member functions that don't modify C
private:
C(C const &);
C& operator=(C const&);
private:
std::vector< T* > v;
};
void init(C& c) { } // cannot be moved inside C
// ...
int main()
{
// bad: two-phase initialization exposed to the clients
C c;
init(c);
// bad: here follows a lot of code that only wants read-only access to c
// but c cannot be declared const
}
建议的内容:
#include <vector>
class T;
class C
{
public:
C() { }
~C( ) { /*calls delete for all elements in v*/ }
// MADE PUBLIC
C(C const &); // <-- NOT DEFINED
// a lot of member functions that modify C
// a lot of member functions that don't modify C
private:
C& operator=(C const&);
private:
vector< T* > v;
};
C init() // for whatever reason object CANNOT be allocated in free memory
{
C c;
// init c
return c;
}
// ...
int main()
{
C const & c = init();
}
这使用最新的 g++(它是唯一的目标编译器)4.1.2 和 4.4.5 进行编译和链接(并且工作)——因为 (N)RVO 永远不会调用复制构造函数;析构函数仅在 main() 结束时调用。
据称该技术非常好,因为复制构造函数不可能被误用(如果它曾经生成过,那将是链接器错误),并且将其公开可以防止编译器抱怨私有一个。
使用这种技巧对我来说看起来真的非常错误,我觉得这与 C++ 精神相矛盾,而且看起来更像是 hack——从这个词的不好的意义上来说。
我的感觉没有足够的论据,所以我现在正在寻找技术细节。
请不要在此处发布教科书 C++ 内容:
- 我知道“三法则”并已通读《圣标准》的 12.8/15 和 12.2;
-
vector<shared_ptr<T> >和ptr_vector<T>都不能用; - 我无法在空闲内存中分配
C并通过C*从init返回它。
谢谢。
【问题讨论】:
-
我假设移动构造对你来说是不可能的?
-
@Konrad Rudolph:很遗憾没有(g++ 4.1.2 是我们应该支持的编译器之一,因此没有 0x 特性)。
-
“将其公开可防止愚蠢的编译器抱怨私有编译器。” - 不是愚蠢的编译器。该标准要求即使复制被省略,复制构造函数也可以访问,因为复制省略是可选的。因此,如果允许它是私有的,那么依赖省略来避免错误的程序无论如何都不会严格符合,在这种情况下,标准要求诊断。编译器正在帮助您编写可移植的代码,诚然违背您的意愿;-)
-
@Steve Jessop:我知道。抱歉,这是“声称的内容”的讽刺部分。我已将其从文本中删除,以防止人们关注不相关的细节。
-
另一种选择:
init可以将(空)boost::optional作为 by-ref 参数,然后将对象构造为此可选项,返回对内部对象的 const 引用升压::可选。在这种情况下,默认 ctor 也将是私有的, init将成为 C 类型的friend。 -- 只是一个想法。
标签: c++ g++ copy-constructor return-value-optimization