我正在熟悉 C++,但我在内存管理方面遇到了问题。在 C 中,每当我想为任意数量的元素保留内存时,无论类型如何,我只需调用 malloc() ,然后手动初始化(通过循环),无论是我想要的值。通缉。使用 C++ 的 new
,一切都会自动初始化。
问题是,我有一个 BattlePoint 类,它有点像这样:
class BattlePoint {
public:
BattlePoint(int x, int y) : x(x), y(y) { };
bool operator==(const BattlePoint &right);
virtual ~BattlePoint();
private:
int x, y;
};
如您所见,它通过初始化程序获取一些 x 和 y 值,然后从中设置自己的 x 和 y 。问题是,这个函数将从一个将分配它们数组的函数中调用:
BattleShip::BattleShip(BattlePoint start, enum shipTypeSize size, enum shipOrientation orientation) : size(size), orientation(orientation) {
points = new BattlePoint[size]; // Here be doubts.
}
所以,我需要我的战舰点来保存一组 BattlePoints,每个 BattlePoints 都有不同的初始化值(例如 0,1; 0,2 ;0,3,等等)。
问题是:如何分配未初始化的内存?
Julian,
PS:我还没有对 new 的工作方式进行任何测试,我简单地阅读了 维基百科关于它的文章 内容如下:
在 C++ 编程语言以及许多基于 C++ 的语言中
语言中,new 是一种动态分配的语言结构
堆上的内存并使用初始化内存
构造函数。除了一种称为“安置新”的形式外,新
尝试在堆上为新数据分配足够的内存。如果
成功,初始化内存并返回地址
新分配和初始化的内存。但是如果 new 无法分配
堆上的内存会抛出 std::bad_alloc 类型的异常。
这消除了显式检查分配结果的需要。
调用delete,它调用析构函数并返回内存
由 new 分配回堆,每次调用 new 时都必须进行
以避免内存泄漏。
放置 new 应该是解决方案,但它没有提及如何做到这一点。
PS 2:我知道这可以通过 stdlib 的向量类来完成,但我故意避免它。
I'm getting acquainted with C++, and I'm having a problem with memory management. In C, whenever I'd want to reserve memory for any number of elements, regardless of type, I would just call malloc()
and then initialize by hand (through a loop), to whichever value I wanted. With C++'s new
, everything is automagically initialized.
Problem is, I've got a BattlePoint class which goes a little something like this:
class BattlePoint {
public:
BattlePoint(int x, int y) : x(x), y(y) { };
bool operator==(const BattlePoint &right);
virtual ~BattlePoint();
private:
int x, y;
};
As you can see, it takes a few x and y values through the initializer and then sets its own x and y from it. The problem is, this function will be called from a function which will allocate an array of them:
BattleShip::BattleShip(BattlePoint start, enum shipTypeSize size, enum shipOrientation orientation) : size(size), orientation(orientation) {
points = new BattlePoint[size]; // Here be doubts.
}
So, I need my BattleShip's point to hold an array of BattlePoints, each one with different initialization values (such as 0,1; 0,2; 0,3, etcetera).
Question is: how could I allocate my memory uninitialized?
Julian,
P.S.: I haven't done any testing regarding the way new
works, I simple read Wikipedia's article on it which says:
In the C++ programming language, as well as in many C++-based
languages, new is a language construct that dynamically allocates
memory on the heap and initialises the memory using the
constructor. Except for a form called the "placement new", new
attempts to allocate enough memory on the heap for the new data. If
successful, it initialises the memory and returns the address to the
newly allocated and initialised memory. However if new cannot allocate
memory on the heap it will throw an exception of type std::bad_alloc.
This removes the need to explicitly check the result of an allocation.
A call to delete, which calls the destructor and returns the memory
allocated by new back to the heap, must be made for every call to new
to avoid a memory leak.
placement new should be the solution, yet it makes no mention on how to do it.
P.S. 2: I know this can be done through stdlib's vector class, but I'm avoiding it on purpose.
发布评论
评论(4)
您需要使用
std::vector
。在这种情况下,您可以push_back
任何您想要的内容,例如,如果您曾经发现自己使用
new[]
、delete
,或delete[]
,立即重构您的程序以删除此类内容。他们几乎在所有可以想象到的方面都非常不安全。相反,请使用资源管理类,例如std::unique_ptr
、std::vector
和std::shared_ptr
。常规
new
可能在涉及unique_ptr
的某些情况下很有用,但要避免使用它。此外,放置新的通常不值得。当然,如果您正在编写一个资源管理类,那么您可能必须将它们用作底层原语,但这种情况很少而且相差很远。编辑:我的错误,我没有看到你问题的最后一行。解决它:
如果您有一些针对标准库的活动,请推出您自己的
向量
替代品。但不要没有vector
类。所有符合标准的编译器都必须提供它,这是有原因的。You need to use a
std::vector
. In this case you canpush_back
whatever you want, e.g.If you ever find yourself using
new[]
,delete
, ordelete[]
, refactor your program immediately to remove such. They are hideously unsafe in virtually every way imaginable. Instead, use resource-managing classes, such asstd::unique_ptr
,std::vector
, andstd::shared_ptr
.Regular
new
can be useful in some situations involvingunique_ptr
, but else avoid it. In addition, placement new is usually not worth it. Of course, if you're writing a resource-managing class, then you may have to use them as underlying primitives, but that's few and very far between.Edit: My mistake, I didn't see the very last line of your question. Addressing it:
If you have some campaign against the Standard Library, then roll your own
vector
replacement. But do not go without avector
class. There's a reason that it must be provided by all conforming compilers.肯定会有疑问!使用
std::vector
。你为什么不呢? 没有没有理由不使用std::vector
,尤其如果它能解决您的问题。我当然会有问题 -
std::vector
如何只分配内存?!operator new
就是答案。当您使用 new 时,会调用该运算符来分配内存。new
用于构造和初始化,而operator new
用于分配(这就是为什么你可以重载它)。Most certainly there will be doubts! Use
std::vector
. Why wouldn't you? There is no reason not to usestd::vector
, especially if it solves your problem.I'm sure the question will come - how does
std::vector
only alloc the memory?!operator new
is the answer. It's the operator that gets called for memory allocation when you usenew
.new
is for construction and initialization, whileoperator new
is for allocation (that's why you can overload it).comp.lang.c++ 常见问题解答提供了有用的信息就此事发表意见,包括试图劝阻您不要使用新的展示位置 - 但如果您真的坚持,它确实有一个关于新的展示位置及其所有陷阱。
The comp.lang.c++ FAQ has useful things to say on the matter, including attempting to dissuade you from using placement new - but if you really insist, it does have a useful section on placement new and all its pitfalls.
为了呼应上述答案,我肯定会向您指出 std::vector ,因为它是最好的解决方案。在
C++
中管理自己的动态数组几乎从来都不是一个好主意,也几乎从来没有必要。但是,要回答直接问题 - 在这种情况下,您可以创建一个默认构造函数和一些修改器以获得所需的效果:
然后您可以像在
C
中习惯的那样初始化它:如果您'如果您对使 BattlePoint 类公开可变感到烦恼,您可以将变异器保持为私有并引入一个专门用于初始化值的友元函数。这是一个稍微复杂一些的概念,因此除非需要,否则我现在将放弃对此进行进一步解释。
既然您问了:)
使用默认构造函数和变异器再次创建您的
BattlePoint
类,但是这次将变异器保留为私有,并声明一个友元函数来使用它们:创建一个包含本地的头文件用于创建
BattlePoint
对象数组的函数。包含标头的任何人都可以使用此函数,但如果命名正确,那么“每个人”都应该知道不要使用它。这个函数和我们的友元函数一起在实现文件中定义,我们将向外界“隐藏”它:
所以你已经有了它。满足您的基本要求的非常复杂的方式。
虽然理论上可以在任何地方调用
create_battlepoint_array()
,但它实际上无法修改已创建的BattlePoint
对象。do_initialize_x_y()
函数本质上隐藏在初始化代码后面的匿名命名空间
中,无法轻松地从程序中的其他任何地方调用。实际上,一旦创建了 BattlePoint 对象(并分两步初始化),就无法进一步修改。To echo the above answers, I would most certainly point you towards
std::vector
as it is the best possible solution. Managing your own dynamic arrays inC++
is almost never a good idea, and is almost never necessary.However, to answer the direct question -- in this situation you can create a default constructor and some mutators to get the desired effect:
Then you can initialize this as you are used to in
C
:If you're bothered by basically making the
BattlePoint
class publically mutable, you can keep the mutators private and introduce a friend function specifically for initializing the values. This is a slightly more involved concept, so I'll forgo further explanation on this for now, unless it is needed.Since you asked :)
Create your
BattlePoint
class again with a default constructor and mutators, however this time leave the mutators private, and declare a friend function to use them:Create a header file that will contain a local function for creating the array of
BattlePoint
objects. This function will be available to anyone that includes the header, but if named properly then "everyone" should know not to use it.This function gets defined in the implementation file, along with our friend function that we will "hide" from the outside world:
So there you have it. A very convoluted way to meet your basic requirements.
While,
create_battlepoint_array()
could in theory be called anywhere, it's actually not capable of modifying an already createdBattlePoint
object. Thedo_initialize_x_y()
function by nature of being hidden in an anonymousnamespace
tucked away behind the initialization code cannot easily be called from anywhere else in your program. In effect, once aBattlePoint
object has been created (and initialized in two steps), it cannot be modified further.