RAII 和未初始化的值
只是一个简单的问题:
如果我有一个简单的向量类:
class Vector
{
public:
float x;
float y;
float z;
};
RAII 概念也适用于此吗? 即提供一个构造函数将所有值初始化为某些值(以防止使用未初始化的值)。
编辑或提供一个构造函数,明确要求用户在对象被实体化之前初始化成员变量。
即
class Vector
{
public:
float x;
float y;
float z;
public:
Vector( float x_, float y_, float z_ )
: x( x_ ), y( y_ ), z( z_ )
{ // Code to check pre-condition; }
};
是否应该使用 RAII 来帮助程序员在使用该值之前忘记初始化该值,或者这是开发人员的责任?
或者说这是看待 RAII 的错误方式?
我故意让这个例子变得简单得可笑。 我真正的问题是回答,例如,一个复合类,例如:
class VectorField
{
public:
Vector top;
Vector bottom;
Vector back;
// a lot more!
};
如您所见...如果我必须编写一个构造函数来初始化每个成员,那就非常乏味了。
想法?
Just a simple question:
if I had a simple vector class:
class Vector
{
public:
float x;
float y;
float z;
};
Doesnt the RAII concept apply here as well? i.e. to provide a constructor to initialize all values to some values (to prevent uninitialized value being used).
EDIT or to provide a constructor that explicitly asks the user to initialize the member variables before the object can be obstantiated.
i.e.
class Vector
{
public:
float x;
float y;
float z;
public:
Vector( float x_, float y_, float z_ )
: x( x_ ), y( y_ ), z( z_ )
{ // Code to check pre-condition; }
};
Should RAII be used to help programmer forgetting to initialize the value before it's used, or is that the developer's responsibility?
Or is that the wrong way of looking at RAII?
I intentionally made this example ridiculously simple. My real question was to answer, for example, a composite class such as:
class VectorField
{
public:
Vector top;
Vector bottom;
Vector back;
// a lot more!
};
As you can see...if I had to write a constructor to initialize every single member, it's quite tedious.
Thoughts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
RAII 中的“R”代表资源。 并非一切都是资源。
许多类(例如 std::vector)都是自初始化的。 你不需要担心这些。
POD 类型不会自初始化,因此将它们初始化为一些有用的值是有意义的。
The "R" in RAII stands for Resource. Not everything is a resource.
Many classes, such as std::vector, are self-initializing. You don't need to worry about those.
POD types are not self initializing, so it makes sense to initialize them to some useful value.
由于
Vector
类中的字段是内置类型,为了确保它们被初始化,您必须在构造函数中执行此操作:现在,如果您的字段是正确编写的类,它们应该自行自动初始化(并在必要时进行清理)。
在某种程度上,这与 RAII 相似且相关,因为 RAII 意味着资源(内存、句柄等)由对象自动获取和清理。
Since the fields in your
Vector
class are built-in types, in order to ensure that they are initialized you'll have to do that in a constructor:Now, if your fields were classes that were properly written, they should automatically initialize (and clean up, if necessary) by themselves.
In a way this is similar and related to RAII in that RAII means that resources (memory, handles, whatever) are acquired and cleaned up automatically by the object.
我不会说 RAII 在这里适用。 记住这些字母代表什么:资源获取就是初始化。 您在这里没有获取任何资源,因此 RAII 不适用。
您可以为
Vector
提供默认构造函数; 这将消除您显式初始化VectorField
的所有成员的需要。 编译器会插入代码来为您执行此操作。I wouldn't exactly say RAII applies here. Remember what the letters stand for: resource acquisition is initialization. You have no resources being acquired here, so RAII doesn't apply.
You could provide a default constructor to
Vector
; that would remove the need for you to explicitly initialize all the members ofVectorField
. The compiler would insert code to do that for you.当您需要执行显式清理,并且希望在隐式清理另一个对象的同时进行该清理时,可以使用 RAII 模式。 内存分配/释放、临界区进入/退出、数据库连接等都可能发生这种情况。在您的示例中,“浮动”会自动清除,因此您无需担心它们。 但是,假设您调用了以下函数来获取向量:
并假设调用者有责任删除返回的向量。 如果您按以下方式调用此代码:
您必须记住释放向量。 如果“东西”是一长段代码,可能会引发异常,或者其中有一堆 return 语句,那么您必须在每个退出点释放向量。 即使您这样做,通过添加另一个“返回”语句或调用某些引发异常的库来维护代码的人也可能不会这样做。 相反,您可以编写这样的类:
然后,您可以像这样获取向量:
然后您不必再担心删除向量,因为当 av 超出范围时,它会被自动删除。 如果您愿意,您也可以编写一个小宏来使“AutoVector av(v)”语法变得更好一点。
这是一个有点做作的例子,但是如果周围的代码很复杂,或者它可以抛出异常,或者有人在中间添加了一个“return”语句,那么“AutoVector”将释放内存就很好了自动地。
您可以对“auto”类执行相同的操作,该类进入其 ctor 中的关键部分并退出其 dtor 等。
You use the RAII pattern when you need to do explicit cleanup, and want that cleanup to occur at the same time as another object is implicitly cleaned up. This can occur for memory allocation/deallocation, critical section entry/exit, database connections, etc. In your example, the "floats" are cleaned up automatically so you don't need to worry about them. However, say you had the following function that you called to obtain vectors:
And say it was the caller's responsibility to delete the returned vector. If you called this code the following way:
You'd have to remember to free the vector. If the "stuff" is a long bit of code, which may throw an exception, or have a bunch of return statements in there, you'd have to free the vector with every exit point. Even if you do it, the person who maintains the code by adding another "return" statement or calling some library that throws an exception may not. Instead, you could write a class like this:
Then, you could obtain the vector like so:
Then you don't have to worry about deleting the vector any more because when av goes out of scope it will be deleted automatically. You can write a little macro to make the "AutoVector av(v)" syntax a little nicer too, if you want.
This is a bit of a contrived example, but if the surrounding code is complicated, or if it can throw exceptions, or someone comes along and adds a "return" statement in the middle, it's nice that the "AutoVector" will free the memory automatically.
You can do the same thing with an "auto" class that enters a critical section in its ctor and exits in its dtor, etc.
如果您不编写构造函数,编译器将为您生成一个默认构造函数,并将这些值设置为默认值(未初始化的值)。 自己提供一个默认构造函数并初始化值,这将是您执行此操作的最佳方法。 我认为这样做并不太复杂。 别太懒了:-)
If you don't write constructor, the compiler will generate a default constructor for you, and set those values to default (uninitialized values). Provide a default constructor yourself and initialize the values there will be your best way to do this. I don't think it's too complicated to do that. Don't be too lazy :-)