"Yeni yerleşim" için ne gibi kullanımlar vardır?


410

Burada hiç kimse C ++ 'ın "yeni yerleşim" kullandı mı? Eğer öyleyse, ne için? Bana sadece bellek eşlemeli donanımda yararlı olacak gibi geliyor.


14
Bu, yalnızca, tahsis edilmiş bellek havuzlarında nesne oluşturucularını çağırmak için aradığım bilgiler. (Bu anahtar kelimelerin umulması, birisinin gelecekte bulmasını kolaylaştıracaktır).
Sideshow Bob

2
Bu kullanılan C ++ 11 Wikipedia makalesinin bir birlik yapıcısı içinde.
HelloGoodbye

@HelloGoodbye, ilginç! Bağladığınız makalede, neden yapmak yerine p = ptatama işlecini kullanamıyorsunuz ? İkisi arasındaki farkları merak ediyorum. Birincisi Point'i çağırır , ikincisi ise kopya yapıcısını çağırır mı? ama neden birinin diğerinden daha iyi olduğu konusunda hala net değilim. Pointnew(&p) Point(pt)operator=Point
Andrei-Niculae Petre

@ Andrei-NiculaePetre Yerleşimi kendim yeni kullanmadım, ancak sanırım o sınıfta bir nesneniz yoksa, kopya oluşturucu ile birlikte kullanmalısınız, aksi takdirde kopya atama işlecini kullanmalısınız. Sınıf önemsiz olmadığı sürece; hangisini kullandığınız önemli değil. Aynı şey nesnenin yok edilmesi için de geçerlidir. Önemsiz sınıflar için bunu doğru şekilde ele almamak garip davranışlara yol açabilir ve hatta bazı durumlarda tanımlanmamış davranışlara neden olabilir .
HelloGoodbye

@ Andrei-NiculaePetre Aslında, Wikipedia makalesindeki örneği oldukça kötü buluyorum, çünkü sadece önceki nesnelerin olmadığını ve bir tane inşa etmeleri gerektiğini varsayar. Yeni U::operator=çağrılmışsa durum böyle değildir .
HelloGoodbye

Yanıtlar:


364

Yeni yerleşim, bellekte önceden ayrılmış bir nesne oluşturmanıza olanak tanır.

Bir nesnenin birden çok örneğini oluşturmanız gerektiğinde bunu en iyileştirme için yapmak isteyebilirsiniz ve yeni bir örneğe her ihtiyaç duyduğunuzda belleği yeniden ayırmamak daha hızlıdır. Bunun yerine, hepsini aynı anda kullanmak istemeseniz bile, birden fazla nesneyi tutabilen bir yığın bellek için tek bir ayırma gerçekleştirmek daha verimli olabilir.

DevX iyi bir örnek veriyor :

Standart C ++, önceden ayrılmış bir arabellek üzerinde bir nesne oluşturan yeni yerleşim işlecini de destekler. Bu, bir bellek havuzu, bir çöp toplayıcı oluştururken veya yalnızca performans ve istisna güvenliği çok önemli olduğunda yararlıdır (bellek zaten tahsis edildiğinden ve önceden ayrılmış bir arabellek üzerine bir nesne oluşturmak daha az zaman alır) :

char *buf  = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi");    // placement new
string *q = new string("hi");          // ordinary heap allocation

Ayrıca, kritik kodun belirli bir bölümünde (örneğin, kalp pili tarafından yürütülen kodda) hiçbir ayırma hatası olmadığından emin olmak isteyebilirsiniz. Bu durumda belleği daha önce ayırmak, ardından kritik bölümdeki yeni yerleşimi kullanmak istersiniz.

Yerleşimde anlaşma yeni

Bellek arabelleğini kullanan her nesneyi yeniden konumlandırmamalısınız. Bunun yerine [] yalnızca orijinal arabelleği silmelisiniz. Daha sonra sınıflarınızın yıkıcılarını manuel olarak çağırmanız gerekir. Bu konuda iyi bir öneri için lütfen Stroustrup'un SSS konusuna bakın: "Yerleşim silme" var mı?


54
Kap nesnelerini (vektör gibi) etkili bir şekilde uygulamak için bu özelliğe ihtiyaç duyduğunuz için kullanımdan kaldırılmamıştır. Kendi kabınızı oluşturmuyorsanız, bu özelliği kullanmanıza gerek yoktur.
Martin York

26
#Makine <memory>
eklemeyi

22
Kesinlikle, delete[]orijinal chararabelleği çağırmak tanımsız bir davranıştır . Yerleşimin kullanılması new, orijinal charnesnelerin depolarını yeniden kullanarak kullanım ömrünü sona erdirdi . Şimdi delete[] bufişaret edilen nesnelerin dinamik türlerini artık statik türleriyle eşleşmiyorsa, tanımlanmamış davranışınız olur. Yerleştirme tarafından kullanılmak üzere başlatılan ham belleği kullanmak operator new/ operator deleteayırmak daha tutarlıdır new.
CB Bailey

31
Kesinlikle bir kalp pili yığın kullanma atlamak istiyorum :-)
Eli Bendersky

15
@RamonZarazua Yanlış başlık, öyle #include <new>.
bit2shift

63

Özel bellek havuzları ile kullanıyoruz. Sadece bir taslak:

class Pool {
public:
    Pool() { /* implementation details irrelevant */ };
    virtual ~Pool() { /* ditto */ };

    virtual void *allocate(size_t);
    virtual void deallocate(void *);

    static Pool::misc_pool() { return misc_pool_p; /* global MiscPool for general use */ }
};

class ClusterPool : public Pool { /* ... */ };
class FastPool : public Pool { /* ... */ };
class MapPool : public Pool { /* ... */ };
class MiscPool : public Pool { /* ... */ };

// elsewhere...

void *pnew_new(size_t size)
{
   return Pool::misc_pool()->allocate(size);
}

void *pnew_new(size_t size, Pool *pool_p)
{
   if (!pool_p) {
      return Pool::misc_pool()->allocate(size);
   }
   else {
      return pool_p->allocate(size);
   }
}

void pnew_delete(void *p)
{
   Pool *hp = Pool::find_pool(p);
   // note: if p == 0, then Pool::find_pool(p) will return 0.
   if (hp) {
      hp->deallocate(p);
   }
}

// elsewhere...

class Obj {
public:
   // misc ctors, dtors, etc.

   // just a sampling of new/del operators
   void *operator new(size_t s)             { return pnew_new(s); }
   void *operator new(size_t s, Pool *hp)   { return pnew_new(s, hp); }
   void operator delete(void *dp)           { pnew_delete(dp); }
   void operator delete(void *dp, Pool*)    { pnew_delete(dp); }

   void *operator new[](size_t s)           { return pnew_new(s); }
   void *operator new[](size_t s, Pool* hp) { return pnew_new(s, hp); }
   void operator delete[](void *dp)         { pnew_delete(dp); }
   void operator delete[](void *dp, Pool*)  { pnew_delete(dp); }
};

// elsewhere...

ClusterPool *cp = new ClusterPool(arg1, arg2, ...);

Obj *new_obj = new (cp) Obj(arg_a, arg_b, ...);

Artık nesneleri tek bir bellek arenasında kümeleyebilir, çok hızlı ancak ayırma yapmayan bir ayırıcı seçebilir, bellek eşlemesini kullanabilir ve havuzu seçip onu bir nesnenin yerleşimine argüman olarak ileterek uygulamak istediğiniz diğer semantikleri kullanabilirsiniz. yeni operatör.


1
Evet. Bu konuda oldukça akıllı davranıyoruz, ancak bu soru için konu dışı.
Don Wakefield

2
@jdkoftinoff Gerçek bir kod örneğine bağlantınız var mı? benim için oldukça ilginç görünüyor!
Victor

@DonWakefield Bu havuzdaki hizalamayı nasıl ele alırsınız? Hizalamayı bir allocate()yere argüman olarak geçirmemelisiniz ?
Mikhail Vasilyev

1
@MikhailVasilyev, gerçek bir uygulamada, elbette bunu halledersiniz. Yalnızca örnek kod.
Don Wakefield

yerleşim geçersiz bir adresse, 0x0 diyelim?
Charlie

51

Tahsisi başlatma işleminden ayırmak istiyorsanız kullanışlıdır. STL, konteyner öğeleri oluşturmak için yeni yerleşimi kullanır.


35

Gerçek zamanlı programlamada kullandım. Sistem başladıktan sonra genellikle herhangi bir dinamik ayırma (veya yeniden konumlandırma) yapmak istemiyoruz, çünkü bunun ne kadar süreceğini garanti etmiyoruz .

Ne yapabilirim bellek büyük bir yığın (sınıf ne gerektirebilir olursa olsun herhangi bir miktarda tutacak kadar büyük) önceden. Sonra, çalışma zamanında şeyleri nasıl yapılacağını anladıktan sonra, yeni yerleştirme, nesneleri istediğim yerde oluşturmak için kullanılabilir. İçinde kullandığımı bildiğim bir durum heterojen dairesel bir tampon oluşturmaya yardımcı olmaktı .

Kesinlikle kalbin zayıflığı için değil, ama bu yüzden sözdizimini biraz gnarly yapıyorlar.


Merhaba TED, sahip olduğunuz çözüm hakkında daha fazla bilgi verir misiniz? Önceden tahsis edilmiş bir çözüm üzerinde düşünüyorum ama çok ilerleme kaydedemiyorum. Şimdiden teşekkür ederim!
Viet

1
Aslında, asıl heterojen dairesel tampon kodu gerçekten doğru olan zor kısımdı. Yeni palsage biraz ürkütücü görünüyor, ancak kıyaslandığında hiç sorun olmadı.
TED

26

Ben alloca () ile yığın tahsis nesneleri oluşturmak için kullandım.

utanmaz fişi: Ben bu konuda blogged burada .


ilginç bir makale, ancak bunu kullanmanın avantajını anladığımdan emin değilim boost::array. Biraz genişletebilir misin?
GrahamS

boost :: array, dizinin boyutunun derleme zamanı sabiti olmasını gerektirir. Bunun bu sınırlaması yoktur.
Ferruccio

2
@Ferruccio Bu çok güzel, makronuzun biraz güvensiz olduğunu fark ettim, yani boyut bir exepression olabilir. Örneğin x + 1 iletilirse, yanlış olan sizeof (type) * x + 1 değerine genişletirsiniz. Daha güvenli hale getirmek için makronuzu desteklemeniz gerekir.
Benj

Tüm nesnelerinizdeki yıkıcıları çağırmak zorunda olduğunuz için bir istisna atılırsa alloca ile kullanmak benim için tehlikeli görünüyor.
CashCow

14

Başkan Geek: BINGO! Tamamen anladınız - tam olarak bunun için mükemmel. Birçok gömülü ortamda, harici kısıtlamalar ve / veya genel kullanım senaryosu, programcıyı bir nesnenin tahsisini başlatma işleminden ayırmaya zorlar. Birlikte toplanan C ++, bu "örnekleme" olarak adlandırır; ancak dinamik veya otomatik ayırma OLMADAN yapıcı eyleminin açıkça başlatılması gerektiğinde, yeni yerleşim bunu yapmanın yoludur. Ayrıca, bir donanım bileşeninin (bellek eşlemeli G / Ç) adresine sabitlenmiş genel bir C ++ nesnesini veya herhangi bir nedenle sabit bir adreste bulunması gereken statik bir nesneyi bulmak için mükemmel bir yoldur.


12

Ben bir Variant sınıfı oluşturmak için kullandım (yani bir dizi farklı türden biri olabilir tek bir değeri temsil edebilir bir nesne).

Variant sınıfı tarafından desteklenen tüm değer türlerinin POD türleri (ör. İnt, float, double, bool) olması durumunda, etiketli bir C stili birleşimi yeterlidir, ancak bazı değer türlerinin C ++ nesneleri olmasını istiyorsanız ( örneğin std :: string), P birliği olmayan veri türleri birliğin parçası olarak bildirilmeyebileceğinden, C birleşimi özelliği çalışmaz.

Bu yüzden bunun yerine yeterince büyük bir bayt dizisi ayırıyorum (örneğin sizeof (the_largest_data_type_I_support)) ve Variant bu tür bir değeri tutmak için ayarlandığında o alanda uygun C ++ nesnesini başlatmak için yeni yerleşimi kullanıyorum. (Ve tabii ki farklı bir POD olmayan veri türünden uzaklaşırken yerleşim önceden silinir)


Hmm, POD olmayan veri türleri , sendika ctor'u sağladığınız sürece bir sendika içinde bildirilebilir - ve hey - bu ctor muhtemelennew POD olmayan alt sınıfını başlatmak için yerleşimi kullanır. Ref: stackoverflow.com/a/33289972/2757035 Bu tekerleği keyfi olarak büyük bir bayt dizisi kullanarak yeniden icat etmek etkileyici bir akrobasi parçası ama tamamen gereksiz görünüyor, Peki, ne kaçırdım? :)
underscore_d

6
Birçok durumda hala desteklenmesi gereken C ++ 11'den önceki tüm C ++ sürümlerini kaçırdınız. :)
Jeremy Friesner

10

Serileştirme sırasında yeni yerleştirme de çok yararlıdır (boost :: serialization ile birlikte). C ++ 10 yıl içinde bu sadece yeni yerleştirilmesi gereken ikinci durumda (üçüncü görüşmeler dahil :)).


9

Global veya statik olarak tahsis edilmiş yapıları yeniden başlatmak istediğinizde de yararlıdır.

Eski C yolu memset() tüm öğeleri 0 olarak ayarlamak . Bunu, vtables ve özel nesne yapıcıları nedeniyle C ++ ile yapamazsınız.

Bu yüzden bazen aşağıdakileri kullanıyorum

 static Mystruct m;

 for(...)  {
     // re-initialize the structure. Note the use of placement new
     // and the extra parenthesis after Mystruct to force initialization.
     new (&m) Mystruct();

     // do-some work that modifies m's content.
 }

1
Bu şekilde yeniden başlatmadan önce uygun bir yıkım yapmanız gerekmez mi?
Kafa Geek

[Yazım için düzenlendi] Genellikle - yaparsınız. Ancak bazen, sınıfın bellek veya diğer kaynakları ayırmadığını bildiğinizde (veya bunları harici olarak yeniden yerleştirdiğinizde - örneğin bellek havuzlarını kullandığınızda), bu tekniği kullanabilirsiniz. V-table işaretlerinin üzerine yazılmamasını garanti eder. - nimrodm 16 saat önce
nimrodm

1
C'de bile, tüm bitlerin 0 olarak ayarlanması kullanıldığında, diğer tipler için değil, yalnızca integral tipler için 0 temsili üretilmesi garanti edilir (boş gösterici sıfırdan farklı gösterime sahip olabilir).
curiousguy

@curiousguy - ilkel türler için haklısınız (hata ayıklama söz konusu olduğunda programı öngörülebilir hale getirir). Ancak, C ++ veri türleri kurucuları çalıştırılacak (yerinde) ve düzgün şekilde başlatılacaktır.
nimrodm

9

Aslında, eklenen öğe sayısı için minimum düzeyde gerekenden daha fazla bellek ayıran her türlü veri yapısının uygulanması gerekir (yani, bir kerede bir düğümü ayıran bağlantılı bir yapı dışında herhangi bir şey).

Al konteynerler gibi unordered_map, vectorya da deque. Bunların hepsi, her bir ekleme için yığın tahsisi gerektirmemek için şimdiye kadar eklediğiniz öğeler için minimum düzeyde gerekenden daha fazla bellek ayırır. vectorEn basit örnek olarak kullanalım .

Yaptığınızda:

vector<Foo> vec;

// Allocate memory for a thousand Foos:
vec.reserve(1000);

... aslında bin Foo yapmaz. Onlar için sadece bellek ayırır / ayırır. Eğer vectoryeni burada yerleşim kullanın vermedi, varsayılan-inşa olurdu Foosbiryere yanı sıra bile bile ilk etapta eklenen asla elemanları kendi yıkıcı çağırmak zorunda.

Tahsis! = İnşaat, Serbest! = Yıkım

Genel olarak yukarıdaki gibi birçok veri yapısını uygulamak için konuşursak, bellek ayırmayı ve öğeleri oluşturmayı bölünmez bir şey olarak ele alamazsınız ve aynı zamanda belleği serbest bırakmayı ve öğeleri yok etmeyi bölünmez bir şey olarak ele alamazsınız.

Gereksiz yere sol ve sağ gereksiz kurucuları ve yıkıcıları çağırmak için bu fikirler arasında bir ayrım olmalıdır ve bu nedenle standart kütüphane std::allocator(hafızayı ayırdığında / serbest bıraktığında öğeleri oluşturmaz veya imha etmez *) fikrini yeni yerleşimi kullanarak öğeleri el ile yapılandıran ve yıkıcıların açık çağrılarını kullanarak öğeleri el ile yok eden, onu kullanan kaplar.

  • Tasarımından nefret ediyorum, std::allocatorama bu sıralamamaktan kaçınacağım farklı bir konu. :-D

Her neyse, çok fazla kullanma eğilimindeyim, çünkü mevcut olanlar açısından inşa edilemeyen bir dizi genel amaçlı standart uyumlu C ++ kapları yazdım. Bunların arasında, birkaç yıl önce yaygın durumlarda yığın tahsislerinden kaçınmak için oluşturduğum küçük bir vektör uygulaması ve bellek verimli bir üçlü (bir seferde bir düğüm ayırmaz) bulunur. Her iki durumda da onları mevcut kapları kullanarak gerçekten uygulayamadım ve bu nedenle placement newgereksiz sol ve sağdaki şeylere yapıcıları ve yıkıcıları gereksiz yere çağırmaktan kaçınmak zorunda kaldım .

Doğal olarak, ücretsiz bir liste gibi, nesneleri ayrı ayrı tahsis etmek için özel ayırıcılar ile çalışırsanız, genellikle placement newbu şekilde de kullanmak istersiniz (istisna güvenliği veya RAII ile uğraşmayan temel örnek):

Foo* foo = new(free_list.allocate()) Foo(...);
...
foo->~Foo();
free_list.free(foo);

8

Bir çekirdek oluşturuyorsanız yararlıdır - diskten veya sayfalı tablodan okuduğunuz çekirdek kodunu nereye yerleştirirsiniz? Nereye atlayacağınızı bilmelisiniz.

Ya da, çok fazla tahsis edilmiş odanız olduğunda ve birkaç yapıyı birbirinizin arkasına yerleştirmek gibi çok nadir durumlarda. Offsetof () operatörüne gerek kalmadan bu şekilde paketlenebilirler. Yine de bunun için başka numaralar da var.

Ayrıca bazı STL uygulamalarının yerleşimi yeni kullandığını düşünüyorum, std :: vector gibi. Bu şekilde 2 ^ n eleman için yer ayırırlar ve her zaman yeniden yer ayırmaları gerekmez.


Bellek ayırmalarını azaltmak, onu kullanmanın birincil nedenlerinden biri ve nesneleri diskten yüklemek gibi "püf noktaları"
lefticus

C ++ ile yazılmış herhangi bir çekirdek bilmiyorum; çoğu çekirdek düz C ile yazılmıştır
Adam Rosenfield

8
İşletim sistemi temellerini öğrendiğim işletim sistemi C ++ ile yazılmıştır: sweb.sourceforge.net
mstrobl

8

Bunun herhangi bir cevapla vurgulanmadığını düşünüyorum, ancak yeni yerleşim için bir başka iyi örnek ve kullanım , bellek parçalanmasını (bellek havuzlarını kullanarak) azaltmaktır. Bu, gömülü ve yüksek kullanılabilirlikli sistemlerde özellikle yararlıdır. Bu son durumda özellikle önemlidir, çünkü 24/365 gün çalışması gereken bir sistem için parçalanma olmaması çok önemlidir. Bu sorunun bellek sızıntısıyla ilgisi yoktur.

Çok iyi bir malloc uygulaması (veya benzer bir bellek yönetim fonksiyonu) kullanıldığında bile, parçalanma ile uzun süre uğraşmak çok zordur. Bir noktada, bellek ayırma / bırakma çağrılarını akıllıca yönetmezseniz, yeniden kullanımı zor olan çok sayıda küçük boşlukla karşılaşabilirsiniz (yeni rezervasyonlara atayın). Dolayısıyla, bu durumda kullanılan çözümlerden biri, uygulama nesneleri için belleği önceden ayırmak için bir bellek havuzu kullanmaktır. Sonrasında bazı nesneler için belleğe her ihtiyacınız olduğunda , önceden ayrılmış bellekte yeni bir nesne oluşturmak için yeni yerleşimi kullanırsınız.

Bu şekilde, uygulamanız başladıktan sonra gereken tüm belleğe zaten sahip olursunuz. Tüm yeni bellek ayırma / bırakma ayrılmış havuzlara gider (her farklı nesne sınıfı için bir tane olmak üzere birkaç havuzunuz olabilir). Boşluk olmayacağından ve sisteminiz parçalanmadan muzdarip olmadan uzun süre (yıl) çalışabileceğinden bu durumda bellek parçalanması olmaz.

Bunu uygulamada özellikle VxWorks RTOS için gördüm, çünkü varsayılan bellek ayırma sistemi parçalanmadan çok acı çekiyor. Bu nedenle, projede standart yeni / malloc yöntemi ile bellek tahsisi temel olarak yasaklanmıştır. Tüm bellek rezervasyonları özel bir bellek havuzuna gitmelidir.


8

Bu tarafından kullanılan std::vector<>çünkü std::vector<>tipik sayısından daha fazla bellek ayırır objectsiçinde vector<>.


7

Bellek eşlemeli dosyalar ile nesneleri depolamak için kullandım.
Bu özel örnek, çok sayıda büyük görüntüyü (belleğe sığmayacak kadar çok) işleyen bir görüntü veritabanıdır.


7

Ben bir "dinamik tip" işaretçi ("Başlık Altında" bölümünde) için hafif bir performans kesmek olarak kullanılan gördüm :

Ama burada küçük türler için hızlı performans elde etmek için kullandığım hileci: eğer tutulan değer bir boşluğun * içine sığabiliyorsa, aslında yeni bir nesne tahsis etmeye zahmet etmiyorum, yeni yerleşimi kullanarak işaretçinin kendisine zorlarım .


Tutulan değer bir boşluğun * içine sığabiliyorsa ne anlama gelir? Void * 'e herhangi bir işaretçi türü atamak her zaman mümkündür. Bize bir örnek verebilir misiniz?
anurag86

@ anurag86: 64 bit makinemde void*8 bayt gerekiyor. Sekiz bayt void*bir bayta işaret etmek biraz aptalca bool. Ancak, aslında gibi , boolüzerine bindirmek tamamen mümkündür . A olarak adlandırdığınız şeyin aslında a (veya a , veya a , vb.) Olduğunu bilmeniz için bir yol bulmanız gerekir . Bağlantı verdiğim makalede bunun nasıl yapılacağı açıklanmaktadır. Ve orijinal soruyu cevaplamak için yerleşim , a'nın beklendiği yerde (veya başka bir tür) oluşturmak için kullanılan özelliktir (daha sonra değeri almak / değiştirmek için dökümler kullanılır). void*union { bool b; void* v }void*boolshortfloatnewboolvoid*
Max Lybbert

@ anurag86: Aynı şey değil, ancak etiketli işaretçilerle ilgilenebilirsiniz ( en.wikipedia.org/wiki/Tagged_pointer ).
Max Lybbert

6

Şebekeden alınan mesajları içeren belleğe dayalı nesneler oluşturmak için kullandım.


5

Genellikle, yeni yerleştirme, 'normal yeni'nin dağıtım maliyetinden kurtulmak için kullanılır.

Kullandığım başka bir senaryo , belge başına tekil bir uygulama yapmak için hala inşa edilecek bir nesneye işaretçiye erişmek istediğim bir yer .



4

Üzerinde koştuğum tek yer bitişik bir tampon ayıran ve sonra gerektiği gibi nesnelerle dolduran kaplarda. Belirtildiği gibi, std :: vector bunu yapabilir ve MFC CArray ve / veya CList'in bazı sürümlerini yaptım (çünkü ilk kez bu yerde koştum). Arabellek aşırı ayırma yöntemi çok kullanışlı bir optimizasyon ve yeni yerleştirme, bu senaryoda nesneleri oluşturmanın hemen hemen tek yoludur. Bazen doğrudan kodunuzun dışında ayrılmış bellek bloklarında nesneler oluşturmak için de kullanılır.

Sık sık gelmese de benzer bir kapasitede kullandım. Yine de C ++ araç kutusu için yararlı bir araçtır.


4

Komut dosyası motorları, yerel arayüzleri komut dosyalarından ayırmak için yerel arayüzde kullanabilir. Örnekler için Angelscript'e (www.angelcode.com/angelscript) bakın.


3

Boyutlarını yanlarında taşımak isteyen diziler için http://xll.codeplex.com adresindeki xll projesinde fp.h dosyasına bakın .

typedef struct _FP
{
    unsigned short int rows;
    unsigned short int columns;
    double array[1];        /* Actually, array[rows][columns] */
} FP;

2

İşte C ++ yerinde oluşturucu için katil kullanım: bir önbellek satırına hizalama ve 2 sınırın diğer güçleri. İşte 5 veya daha az tek döngü talimatları ile 2 sınırın herhangi bir gücüne ultra hızlı işaretçi hizalama algoritmam :

/* Quickly aligns the given pointer to a power of two boundary IN BYTES.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param boundary_byte_count The boundary byte count that must be an even
power of 2.
@warning Function does not check if the boundary is a power of 2! */
template <typename T = char>
inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) {
  uintptr_t value = reinterpret_cast<uintptr_t>(pointer);
  value += (((~value) + 1) & (boundary_byte_count - 1));
  return reinterpret_cast<T*>(value);
}

struct Foo { Foo () {} };
char buffer[sizeof (Foo) + 64];
Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo ();

Şimdi bu sadece yüzüne bir gülümseme koymuyor (:-). I ♥♥♥ C ++ 1x

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.