我正在尝试分配一个大小为 size 的内存块,它需要 Alignment 对齐,而在编译时可能未定义大小。我知道存在 _aligned_alloc、posix_memalign、_mm_alloc 等例程,但我不想使用它们,因为它们会降低代码的可移植性。
C++11 提供了一个例程 std::align 和一个类 std::aligned_storage,我可以从中检索 POD 类型进行分配一个将符合我的要求的元素。然而,我的目标是创建一个分配器,它将分配一个 size 大小的内存块(不仅仅是单个元素),该内存块将被对齐。
这可能使用 std::align 吗?我问的原因是因为 std::align 移动指针,使用该指针的类将为分配器提供指向移动地址的指针以进行释放,这将是无效的。有没有办法以这种方式创建 aligned_allocator?
最佳答案
编辑:经过 OP 的澄清后,原来的答案似乎跑题了;仅供引用,它保留在本答案的末尾。
实际上,答案很简单:您只需要保留一个指向存储 block 和第一项的指针即可。
这实际上不需要有状态的分配器(即使在 C++03 中也是可能的,尽管使用自定义 std::align 例程)。诀窍是分配器不需要只要求系统提供足够的内存来存储用户数据。它完全可以为了自己的簿记目的而要求多一点。
所以,我们在这里创建一个对齐的分配器;为简单起见,我将重点介绍分配/解除分配例程。
template <typename T>
class aligned_allocator {
// Allocates block of memory:
// - (opt) padding
// - offset: ptrdiff_t
// - T * n: T
// - (opt) padding
public:
typedef T* pointer;
typedef size_t size_type;
pointer allocate(size_type n);
void deallocate(pointer p, size_type n);
}; // class aligned_allocator
现在是分配例程。大量内存摆弄,毕竟这是分配器的核心!
template <typename T>
auto aligned_allocator<T>::allocate(size_type n) -> pointer {
size_type const alignment = std::max(alignof(ptrdiff_t), alignof(T));
size_type const object_size = sizeof(ptrdiff_t) + sizeof(T)*n;
size_type const buffer_size = object_size + alignment;
// block is correctly aligned for `ptrdiff_t` because `std::malloc` returns
// memory correctly aligned for all built-ins types.
void* const block = std::malloc(buffer_size);
if (block == nullptr) { throw std::bad_alloc{}; }
// find the start of the body by suitably aligning memory,
// note that we reserve sufficient space for the header beforehand
void* storage = reinterpret_cast<char*>(block) + sizeof(ptrdiff_t);
size_t shift = buffer_size;
void* const body = std::align(alignment, object_size, storage, shift);
// reverse track to find where the offset field starts
char* const offset = reinterpret_cast<char*>(body) - sizeof(ptrdiff_t);
// store the value of the offset (ie, the result of body - block)
*reinterpret_cast<ptrdiff_t*>(offset) = sizeof(ptrdiff_t) + shift;
// finally return the start of the body
return reinterpret_cast<ptrdiff_t>(body);
} // aligned_allocator<T>::allocate
幸运的是,释放例程要简单得多,它只需要读取偏移量并应用它。
template <typename T>
void aligned_allocator<T>::deallocate(pointer p, size_type) {
// find the offset field
char const* header = reinterpret_cast<char*>(p) - sizeof(ptrdiff_t);
// read its value
ptrdiff_t const offset = *reinterpret_cast<ptrdiff_t*>(header);
// apply it to find start of block
void* const block = reinterpret_cast<char*>(p) - offset;
// finally deallocate
std::free(block);
} // aligned_allocator<T>::deallocate
其他例程不需要知道内存布局,因此编写它们很简单。
原答案:
template <typename T>
class Block {
public:
Block(Block const&) = delete;
Block& operator=(Block const&) = delete;
explicit Block(size_t n);
~Block();
private:
void* _storage;
T* _begin;
T* _end;
}; // class Block
template <typename T>
Block<T>::Block(size_t n) {
size_t const object_size = n * sizeof(T);
size_t const buffer_size = object_size + alignof(T);
_storage = std::malloc(size);
void* stock = _storage;
size_t shift = buffer_size;
std::align(alignof(T), object_size, stock, shift);
_begin = _end = reinterpret_cast<T*>(stock);
} // Block<T>::Block
template <typename T>
Block<T>::~Block() {
for (; _end != _begin; --_end) {
(_end - 1)->~T();
}
std::free(_storage);
} // Block<T>::~Block
关于c++ - std::align 和 std::aligned_storage 用于内存块的对齐分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17378444/
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
通过rubykoans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序
我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案
当我使用has_one时,它工作得很好,但在has_many上却不行。在这里您可以看到object_id不同,因为它运行了另一个SQL来再次获取它。ruby-1.9.2-p290:001>e=Employee.create(name:'rafael',active:false)ruby-1.9.2-p290:002>b=Badge.create(number:1,employee:e)ruby-1.9.2-p290:003>a=Address.create(street:"123MarketSt",city:"SanDiego",employee:e)ruby-1.9.2-p290
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我