如何解决在 Ada 中,placement new 相当于什么?
我试图通过编写一组管理动态数组的过程来学习 Ada,但我不知道如何去做。在 C++ 中,我可以轻松地将任意对象放入内存中,如下所示:
#include <new>
#include <iostream>
class object {
private:
int value;
public:
~object() noexcept { std::cout << "<> "; }
object(int value) noexcept : value(value) { std::cout << object::value << ' '; }
};
constexpr auto size = 16;
int main() {
auto buffer = static_cast<object*>(::operator new(size * sizeof(object)));
for (auto offset = 0; offset < size; offset++)
new (buffer + offset) object(offset);
for (auto offset = 0; offset < size; offset++)
(buffer + offset)->~object();
::operator delete(buffer);
}
在 Ada 中是否有等价于这种类型的“分配 x * sizeof(y) 并初始化 x y 项”操作?
解决方法
是的。 Ada 允许动态内存分配。分配器的主题在 section 4.8 of the Ada Reference Manual 中处理。参考手册中的示例是:
16 Examples of allocators: 17 new Cell'(0,null,null) -- initialized explicitly,see 3.10.1 new Cell'(Value => 0,Succ => null,Pred => null) -- initialized explicitly new Cell -- not initialized 18 new Matrix(1 .. 10,1 .. 20) -- the bounds only are given new Matrix'(1 .. 10 => (1 .. 20 => 0.0)) -- initialized explicitly 19 new Buffer(100) -- the discriminant only is given new Buffer'(Size => 80,Pos => 0,Value => (1 .. 80 => 'A')) -- initialized explicitly
必须先声明要分配的类型,然后是访问类型才能访问分配的内存。
以下示例对整数数组执行并行加法。数组是动态分配的,因为使用分配器可以分配比在堆栈上分配的数组大得多的数组。
包规范定义了数组类型和访问类型。
package Parallel_Addition is
type Data_Array is array(Integer range <>) of Integer;
type Data_Access is access all Data_Array;
function Sum(Item : in not null Data_Access) return Integer;
end Parallel_Addition;
包体使用两个任务对数组的内容求和。
package body Parallel_Addition is
---------
-- Sum --
---------
function Sum (Item : in not null Data_Access) return Integer is
task type Adder is
entry Set (Min : Integer; Max : Integer);
entry Report (Value : out Integer);
end Adder;
task body Adder is
Total : Integer := 0;
First : Integer;
Last : Integer;
begin
accept Set (Min : Integer; Max : Integer) do
First := Min;
Last := Max;
end Set;
for I in First .. Last loop
Total := Total + Item (I);
end loop;
accept Report (Value : out Integer) do
Value := Total;
end Report;
end Adder;
A1 : Adder;
A2 : Adder;
R1 : Integer;
R2 : Integer;
Mid : constant Integer := (Item'Length / 2) + Item'First;
begin
A1.Set (Min => Item'First,Max => Mid);
A2.Set (Min => Mid + 1,Max => Item'Last);
A1.Report (R1);
A2.Report (R2);
return R1 + R2;
end Sum;
end Parallel_Addition;
正如你在上面看到的,数组元素的访问没有通过访问类型取消引用数组的特殊语法。这个程序的“主要”程序是
with Parallel_Addition; use Parallel_Addition;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
procedure Parallel_Addition_Test is
The_Data : Data_Access := new Data_Array (1 .. Integer'Last);
Start : Time;
Stop : Time;
The_Sum : Integer;
begin
The_Data.all := (others => 1);
Start := Clock;
The_Sum := Sum (The_Data);
Stop := Clock;
Put_Line ("The sum is: " & Integer'Image (The_Sum));
Put_Line
("Addition elapsed time is " &
Duration'Image (Stop - Start) &
" seconds.");
Put_Line
("Time per addition operation is " &
Float'Image(Float(Stop - Start) / Float(The_Data'Length)) &
" seconds.");
end Parallel_Addition_Test;
这个程序在我的 Windows 10 计算机上运行时的输出是:
The sum is: 2147483647
Addition elapsed time is 5.628780600 seconds.
Time per addition operation is 2.62111E-09 seconds.
,
在 Ada 中,您可以编写自定义的“”(或子池) 在其中重新定义 Allocate 函数以使用缓冲区。然后将访问类型“绑定”到存储池对象。
with System.Storage_Pools;
with System.Storage_Elements;
procedure Main is
type My_Storage_Pool is new System.Storage_Pools.Root_Storage_Pool with record
Buffer : System.Storage_Elements.Storage_Array (1 .. 1024);
Offset : System.Storage_Elements.Storage_Count := 1;
end record;
overriding procedure Allocate
(Self : in out My_Storage_Pool;
Address : out System.Address;
Size : System.Storage_Elements.Storage_Count;
Alignment : System.Storage_Elements.Storage_Count);
overriding procedure Deallocate
(Self : in out My_Storage_Pool;
Address : System.Address;
Size : System.Storage_Elements.Storage_Count;
Alignment : System.Storage_Elements.Storage_Count) is null;
overriding function Storage_Size
(Self : My_Storage_Pool)
return System.Storage_Elements.Storage_Count is (Self.Buffer'Length);
procedure Allocate
(Self : in out My_Storage_Pool;
Address : out System.Address;
Size : System.Storage_Elements.Storage_Count;
Alignment : System.Storage_Elements.Storage_Count)
is
use type System.Storage_Elements.Storage_Count;
begin
Address := Self.Buffer (Self.Offset)'Address;
Self.Offset := Self.Offset + Size;
end Allocate;
Pool : My_Storage_Pool;
type Object is null record;
type Object_Access is access Object with Storage_Pool => Pool;
X : Object_Access := new Object;
begin
null;
end Main;
此外,对于 untagged 类型,您可以使用 Address
子句将对象放置到给定地址。这要简单得多。但是这种方式对象初始化不起作用,因此标记类型的对象不会获得虚拟表指针:
Buffer : Stream_Element_Array (1..1024);
Object : My_Object_Type
with Import,Address => Buffer (Offset)'Address;
-- Here Object'Tag is unassigned and dispatching won't work
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。