C++ 构造函数可以返回 NULL 值吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2859062/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can a constructor return a NULL value?
提问by Sanctus2099
I know constructors don't "return" anything but for instance if I call CMyClass *object = new CMyClass()
is there any way to make object to be NULL if the constructor fails? In my case I have some images that have to be loaded and if the file reading fails I'd like it to return null. Is there any way to do that?
Thanks in advance.
我知道构造函数不会“返回”任何东西,但是例如,如果我调用,CMyClass *object = new CMyClass()
如果构造函数失败,是否有任何方法可以使对象为 NULL?就我而言,我有一些必须加载的图像,如果文件读取失败,我希望它返回 null。有没有办法做到这一点?
提前致谢。
采纳答案by Michael Mrozek
I agree with everyone else that you should use exceptions, but if you do really need to use NULL for some reason, make the constructor private and use a factory method:
我同意其他人的意见,您应该使用异常,但是如果出于某种原因确实需要使用 NULL,请将构造函数设为私有并使用工厂方法:
static CMyClass* CMyClass::create();
This means you can't construct instances normally though, and you can't allocate them on the stack anymore, which is a pretty big downside.
这意味着您不能正常构造实例,并且不能再在堆栈上分配它们,这是一个很大的缺点。
回答by David Rodríguez - dribeas
Constructors do not return values. They initialize an object and the only way of reporting errors is through an exception.
构造函数不返回值。它们初始化一个对象,报告错误的唯一方法是通过异常。
Note that the constructor does not make any type of memory management. Memory is allocated externally and then the constructor is called to initialize it. And that memory can be dynamically allocated (type *x = new type;
) but it might as well be in the stack (type x;
) or a subobject of a more complex type. In all but the first case, null does not make sense at all.
请注意,构造函数不进行任何类型的内存管理。内存在外部分配,然后调用构造函数对其进行初始化。并且该内存可以动态分配 ( type *x = new type;
) 但它也可能位于堆栈 ( type x;
) 或更复杂类型的子对象中。除了第一种情况,null 根本没有意义。
回答by AraK
The "correct"** way is to throw an exception.
“正确”** 方法是抛出异常。
** You can provide a member function like is_valid
that you can check after constructing an object but that's just not idiomatic in C++.
** 你可以提供一个成员函数is_valid
,你可以在构造一个对象后检查,但这在 C++ 中不是惯用的。
回答by user151019
The way to do this is if you find something not working in your constructor you should throw an exception. This is what happens if C++ cannot allocate memory for your object - it throws std::bad_alloc. You should use std::exception or a subclass.
这样做的方法是,如果您发现构造函数中的某些内容不起作用,则应该抛出异常。如果 C++ 无法为您的对象分配内存,则会发生这种情况 - 它会抛出 std::bad_alloc。您应该使用 std::exception 或子类。
回答by Jason Kleban
Could use a static factory method instead? When converting between types, I might make a public static CMyClass Convert(original) and return null if original is null. You'd probably still want to throw exceptions for invalid data though.
可以改用静态工厂方法吗?在类型之间转换时,我可能会创建一个公共静态 CMyClass Convert(original) 并在 original 为 null 时返回 null。不过,您可能仍然希望为无效数据抛出异常。
回答by Joshua
In bad taste.
味道不好。
Well if you actually want to do this, overload new, have new call a private constructor that does no initialization, do the initialization in new, and have new return null if initialization fails.
好吧,如果你真的想这样做,重载new,让new调用一个不初始化的私有构造函数,在new中进行初始化,如果初始化失败,new返回null。
回答by Steven Sudit
Rather than telling you how to get a constructor to return null, or how to fake it, let me suggest an alternative: offer a way to avoid throwing an exception, such as by delayed initialization or a non-throwing constructor. Once you do this, though, you need to have a way to check validity and to ensure that any attempt to usean invalid instance does throw an exception. In other words, you're delaying the exception, not avoiding it entirely.
与其告诉您如何让构造函数返回 null 或如何伪造它,不如让我提出一个替代方案:提供一种避免抛出异常的方法,例如延迟初始化或不抛出构造函数。但是,一旦执行此操作,您就需要有一种方法来检查有效性并确保任何使用无效实例的尝试都会引发异常。换句话说,您是在延迟异常,而不是完全避免它。
Here's how: You already have a constructor that takes a file path and loads it, throwing on failure. Move the guts into a Load method that takes the file path and returns a bool to indicate success. Then change the constructor so it simply calls Load and throws on false. In Load, make sure to immediately return false if the instance is properly initialized. Then add a default destructor and an IsValid method.
方法如下:您已经有一个构造函数,它接受一个文件路径并加载它,但失败了。将胆量移到 Load 方法中,该方法采用文件路径并返回一个 bool 以表示成功。然后更改构造函数,使其简单地调用 Load 并抛出 false。在 Load 中,如果实例正确初始化,请确保立即返回 false。然后添加一个默认的析构函数和一个 IsValid 方法。
Per Dennis: Now add a second constructor that takes a boolean to control whether an exception is thrown, and consider relegating Load to private, in which case you would likewise remove the default constructor.
Per Dennis:现在添加第二个构造函数,它接受一个布尔值来控制是否抛出异常,并考虑将 Load 降级为私有,在这种情况下,您同样需要删除默认构造函数。
This gives you all that you can ask for, without making unmaintainable code. It should look something like this:
这为您提供了您可以要求的一切,而不会编写不可维护的代码。它应该是这样的:
// Per Dennis, should go away if Load becomes private.
Image()
{
_valid = false;
}
Image(const string& filepath)
{
if (!Load(filepath))
throw new exception("Cannot open image.");
}
// Per Dennis.
Image(const string& filepath, bool doThrow)
{
if (!Load(filepath) && doThrow)
throw new exception("Cannot open image.");
}
// Per Dennis, this should probably be made private now.
bool Load(const string& filepath)
{
if (_valid)
return false;
// Try to load...
_valid = WhetherItLoadedExpression;
return _valid;
}
bool IsValid()
{
return _valid;
}
void Draw()
{
if (!IsValid())
throw new exception("Invalid object.");
// Draw...
}
edit
编辑
See below for changes made in response to Dennis' comment.
请参阅下文,了解针对丹尼斯的评论所做的更改。
回答by karlphillip
if I call
CMyClass* object = new CMyClass()
is there any way to make object to be NULL if the constructor fails?
如果我调用,
CMyClass* object = new CMyClass()
如果构造函数失败,是否有任何方法可以使对象为 NULL?
I see what you mean! There are lots of C++ libraries out there that make heavy use of dynamically allocated memory and implement this idea (such as QtGstreamer), so its definitely possible to write your code to look like:
我明白你的意思了!有很多 C++ 库大量使用动态分配的内存并实现了这个想法(例如QtGstreamer),因此绝对可以编写如下代码:
CMyClass* object = new CMyClass()
if (!object)
{
// FAILED!
}
However, its not the constructor of the object that returns NULL
. It's an overloaded version of operator new
.
但是,它不是返回 的对象的构造函数NULL
。它是operator new
.
回答by JDel
This can be done a little hackish by overriding the new operator
这可以通过覆盖 new 运算符来完成
See this example:
看这个例子:
http://coliru.stacked-crooked.com/a/62e097827724f91e
http://coliru.stacked-crooked.com/a/62e097827724f91e
Technically it's no longer a constructor but it does behave the way you want it.
从技术上讲,它不再是一个构造函数,但它确实按照你想要的方式运行。
回答by sergiol
Present message should be a comment on the answer, but there is not a good place to see code!
现在留言应该是对答案的评论,但是没有看到代码的好地方!
I've stumbled across the following code:
我偶然发现了以下代码:
std::ofstream f(m_filename);
if (!f)
return false;
and saw it actually passing on the return false;
statement. And said "What? Did the constructor return NULL
?"
并看到它实际上传递了return false;
声明。然后说:“什么?构造函数返回了NULL
吗?”
I was being mislead, as the if
makes an implicit call to the operator bool()
of the ofstream
class.
我被误导了,因为if
它隐含地调用operator bool()
了ofstream
类的 。