Lun*_*oul 3 c++ memory-leaks memory-management
我一直在使用这种方法从C++中的函数返回引用.但是,我怀疑有更好的模式来执行这样的操作.另外,我猜这种方法意味着内存泄漏.
class A {};
A& return_instance_of_A(){
A* result = new A();
return *result;
}
Run Code Online (Sandbox Code Playgroud)
使用shared_ptr会是更好的选择吗?
从函数返回引用的推荐方法是什么?
从语法上讲,只需返回一个引用.
int& myFunction() { .... }
Run Code Online (Sandbox Code Playgroud)
引用的行为几乎与指针一样.你的例子有一些问题.
您分配的对象需要在某个时候删除,通常这是通过指针处理的.通常,接收以后需要的引用非常奇怪delete.
在现代C++中,以这种断开连接的方式处理内存分配也是不常见的.我同意你的回复建议shared_ptr.这使得所有权显而易见,并且不会像您的示例那样无意中泄漏内存.
您的示例不一定会导致内存泄漏,但它很尴尬,因为您对调用程序(即delete返回的对象)放置了一些未由编译器强制执行的要求.
编辑,以解决建议按值返回的人:它只取决于调用者的要求.许多小/实用对象喜欢Rectangle或者Size意味着按价值传递,这使事情变得非常简单和直观.
一个实际的例子是这样的:
inline Rect make_square_rect(int left, int right, int width)
{
return Rect(left, right, width, width);
}
Run Code Online (Sandbox Code Playgroud)
绝对是这样的函数最好按值返回.注意这个功能与构造函数的相似程度如何......
对于像其它更大,更坚定和有状态的对象TcpConnection或者Window,这种相似性变得更清晰.所有权和内存管理的问题被放大了.
任何无法复制/移动的内容都是如此.
因此,新的创造Window不能像a一样随意Rect.Rect从像你这样的函数创建一个并不真正关心所有权的问题,因为复制Rect对象的成本和简单程度是多么便宜.但是如果你的函数返回类似的东西Window,那么你的函数自然会解决所有权问题 - 可能是通过返回一个shared_ptr<Window>.
编辑#2:构造函数性质
在回应您的评论时,我将再次指出这些函数与构造函数非常相似.这些函数实际上只是设置一个首次使用的对象 - 但我们坐在这里试图决定该函数应该如何处理所有权/复制.
实际上,这正是构造函数应该做的事情.
struct BigInteger
{
BigInteger(int initial_value) { ... }
};
Run Code Online (Sandbox Code Playgroud)
在这里,构造函数不需要处理我们正在讨论的概念.来电者决定他想要如何处理所有权:
BigInteger* ptr = new BigInteger(42);
BigInteger val = BigInteger(42);
Run Code Online (Sandbox Code Playgroud)
作为构造函数编写,这可以处理这两种情况.我看到它的方式,这种情况的烦人的事情是构造函数不能在C++中命名.例如,假设您正在编写这些函数:
BigInteger make_big_integer_by_multiplying(int a, int b) { ... }
BigInteger make_big_integer_by_adding(int a, int b) { ... }
Run Code Online (Sandbox Code Playgroud)
将这些变成构造函数是没有好办法的.您需要一个符号名来区分这些函数,而构造函数不能有名称.
作为一个独立的功能,你被迫决定所有权行为.你必须权衡利弊,主要是:考虑调用者如何使用该对象.如果调用者想要一个持久的,有状态的长寿命对象,那么返回一个shared_ptr.如果调用者将该对象用作中间值,值类型(我BigInteger绝对认为是),则按值返回.