Apa kegunaan untuk "penempatan baru"?

411

Adakah orang di sini yang pernah menggunakan "penempatan baru" C ++? Jika demikian, untuk apa? Sepertinya saya hanya akan berguna pada perangkat keras yang dipetakan dengan memori.

Kepala Geek
sumber
14
Ini hanya informasi yang saya cari, untuk memanggil konstruktor objek pada peningkatan kumpulan memori yang dialokasikan. (Berharap kata kunci ini akan membuat seseorang lebih mudah ditemukan di masa depan).
Sonton Bob
2
Ini digunakan dalam artikel Wikipedia bahasa C ++ 11 dalam konstruktor suatu kesatuan.
HelloGoodbye
@ Halo Selamat tinggal, menarik! Dalam artikel yang Anda tautkan, mengapa Anda tidak bisa hanya melakukan p = ptdan menggunakan operator penugasan Pointalih-alih melakukan new(&p) Point(pt)? Saya ingin tahu perbedaan antara keduanya. Apakah mantan memanggil operator=Point, sedangkan yang kedua memanggil copy constructor Point? tapi saya masih tidak begitu jelas mengapa yang satu lebih baik dari yang lain.
Andrei-Niculae Petre
@ Andrei-NiculaePetre Saya belum pernah menggunakan penempatan baru, tetapi saya kira Anda harus menggunakannya — bersama-sama dengan konstruktor salin — jika Anda saat ini tidak memiliki objek kelas itu, jika tidak, Anda harus menggunakan operator penugasan salinan. Kecuali jika kelasnya sepele; maka tidak masalah yang mana yang Anda gunakan. Hal yang sama berlaku untuk penghancuran objek. Gagal menangani ini dengan benar untuk kelas non-sepele sangat mungkin menyebabkan perilaku aneh, dan bahkan dapat menyebabkan perilaku tidak terdefinisi dalam beberapa situasi.
HelloGoodbye
@ Andrei-NiculaePetre Sebenarnya, saya menemukan contoh di artikel Wikipedia cukup buruk, karena hanya mengasumsikan bahwa tidak ada objek sebelumnya dan bahwa mereka perlu membangun satu. Ini tidak terjadi jika U::operator=baru saja dipanggil.
HelloGoodbye

Jawaban:

365

Penempatan baru memungkinkan Anda membuat objek dalam memori yang sudah dialokasikan.

Anda mungkin ingin melakukan ini untuk optimasi ketika Anda perlu membangun beberapa instance objek, dan lebih cepat untuk tidak mengalokasikan kembali memori setiap kali Anda membutuhkan instance baru. Sebagai gantinya, mungkin lebih efisien untuk melakukan alokasi tunggal untuk sepotong memori yang dapat menampung banyak objek, meskipun Anda tidak ingin menggunakan semuanya sekaligus.

DevX memberikan contoh yang baik :

Standar C ++ juga mendukung penempatan operator baru, yang membangun objek pada buffer yang dialokasikan sebelumnya. Ini berguna ketika membangun kumpulan memori, pengumpul sampah, atau hanya ketika kinerja dan keselamatan pengecualian adalah yang terpenting (tidak ada bahaya kegagalan alokasi karena memori telah dialokasikan, dan membangun objek pada buffer yang dialokasikan sebelumnya membutuhkan waktu lebih sedikit) :

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

Anda mungkin juga ingin memastikan tidak ada kegagalan alokasi pada bagian tertentu dari kode kritis (misalnya, dalam kode yang dijalankan oleh alat pacu jantung). Dalam hal ini Anda ingin mengalokasikan memori lebih awal, lalu gunakan penempatan baru dalam bagian kritis.

Deallokasi dalam penempatan baru

Anda seharusnya tidak membatalkan alokasi setiap objek yang menggunakan buffer memori. Sebaliknya Anda harus menghapus [] hanya buffer asli. Anda kemudian harus memanggil destruktor kelas Anda secara manual. Untuk saran yang bagus tentang ini, silakan lihat FAQ Stroustrup di: Apakah ada "penghapusan penempatan" ?

Brian R. Bondy
sumber
54
Ini tidak ditinggalkan karena Anda memerlukan fitur ini untuk mengimplementasikan objek kontainer secara efisien (seperti vektor). Jika Anda tidak membuat wadah sendiri, Anda tidak perlu menggunakan fitur ini.
Martin York
26
Juga sangat penting untuk mengingat untuk #include <memory>, jika tidak, Anda mungkin mengalami beberapa sakit kepala yang mengerikan di beberapa platform yang tidak secara otomatis mengenali penempatan baru
Ramon Zarazua B.
22
Sebenarnya, ini adalah perilaku yang tidak terdefinisi untuk memanggil buffer delete[]asli char. Menggunakan penempatan newtelah mengakhiri masa pakai charobjek asli dengan menggunakan kembali penyimpanannya. Jika sekarang Anda memanggil delete[] buftipe dinamis dari objek yang ditunjukkan tidak lagi cocok dengan tipe statisnya, maka Anda memiliki perilaku yang tidak terdefinisi. Itu lebih konsisten untuk menggunakan operator new/ operator deletemengalokasikan memori mentah dimasukkan untuk digunakan oleh penempatan new.
CB Bailey
31
Saya pasti akan melewatkan menggunakan tumpukan di alat pacu jantung :-)
Eli Bendersky
15
@RamonZarazua Header salah, ini #include <new>.
bit2shift
63

Kami menggunakannya dengan kumpulan memori khusus. Hanya sebuah sketsa:

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, ...);

Sekarang Anda dapat mengelompokkan objek dalam satu arena memori tunggal, pilih pengalokasi yang sangat cepat tetapi tidak ada alokasi, gunakan pemetaan memori, dan semantik lain yang ingin Anda terapkan dengan memilih pool dan meneruskannya sebagai argumen penempatan objek. operator baru.

Don Wakefield
sumber
1
Ya. Kami cukup pintar tentang hal itu, tetapi di luar topik untuk pertanyaan ini.
Don Wakefield
2
@ jdkoftinoff apakah Anda memiliki tautan ke contoh kode yang sebenarnya? sepertinya cukup menarik untukku!
Victor
@ DonWakefield Bagaimana Anda menangani perataan di kolam ini? Tidakkah seharusnya Anda meneruskan keberpihakan sebagai argumen ke allocate()suatu tempat?
Mikhail Vasilyev
1
@MikhailVasilyev, dalam implementasi nyata, Anda tentu saja akan mengatasinya. Kode contoh saja.
Don Wakefield
bagaimana jika penempatannya adalah alamat yang tidak valid, katakan 0x0?
Charlie
51

Ini berguna jika Anda ingin memisahkan alokasi dari inisialisasi. STL menggunakan penempatan baru untuk membuat elemen wadah.

MSN
sumber
35

Saya telah menggunakannya dalam pemrograman waktu nyata. Kami biasanya tidak ingin melakukan alokasi dinamis (atau deallokasi) setelah sistem dimulai, karena tidak ada jaminan berapa lama waktu yang diperlukan.

Apa yang bisa saya lakukan adalah mengalokasikan memori dalam jumlah besar (cukup besar untuk menampung jumlah berapapun yang dibutuhkan oleh kelas). Kemudian, begitu saya mengetahui pada saat runtime bagaimana membangun sesuatu, penempatan baru dapat digunakan untuk membangun objek tepat di tempat yang saya inginkan. Satu situasi yang saya tahu saya gunakan adalah untuk membantu membuat buffer melingkar yang heterogen .

Itu tentu saja bukan untuk orang yang lemah hati, tetapi karena itulah mereka membuat sintaksis untuknya secara agak degil.

TED
sumber
Hai TED, bisakah Anda berbagi lebih banyak tentang solusi yang Anda miliki. Saya sedang memikirkan solusi pra-alokasi tetapi belum mendapat banyak kemajuan. Terima kasih sebelumnya!
Viet
1
Nah, kode buffer sirkular hetrogenious yang sebenarnya adalah bagian yang sulit untuk diperbaiki. Pagar yang baru terlihat sedikit mengerikan, tetapi dengan perbandingan itu tidak ada masalah sama sekali.
TED
26

Saya telah menggunakannya untuk membangun objek yang dialokasikan pada stack melalui alokasi ().

plug shameless: Saya ngeblog tentang hal itu di sini .

Ferruccio
sumber
artikel yang menarik, tapi saya tidak yakin saya mengerti keuntungan menggunakan ini boost::array. Bisakah Anda sedikit mengembangkannya?
GrahamS
boost :: array membutuhkan ukuran array sebagai konstanta waktu kompilasi. Ini tidak memiliki batasan itu.
Ferruccio
2
@Ferruccio Ini sangat keren, saya memang melihat bahwa makro Anda sedikit tidak aman, yaitu ukuran bisa menjadi suatu tekanan. Jika x +1 dilewatkan misalnya Anda akan memperluas ke sizeof (tipe) * x +1 yang akan salah. Anda perlu membuat bracket makro Anda agar lebih aman.
Benj
Menggunakan dengan dialokasikan akan berbahaya bagi saya jika ada pengecualian karena Anda harus memanggil destruktor pada semua objek Anda.
CashCow
14

Head Geek: BINGO! Anda benar-benar mendapatkannya - itulah yang tepat untuk itu. Dalam banyak lingkungan tertanam, kendala eksternal dan / atau keseluruhan skenario penggunaan memaksa pemrogram untuk memisahkan alokasi suatu objek dari inisialisasi. Disatukan, C ++ menyebut ini "instantiation"; tetapi setiap kali tindakan konstruktor harus secara eksplisit dipanggil TANPA alokasi dinamis atau otomatis, penempatan baru adalah cara untuk melakukannya. Ini juga cara sempurna untuk menemukan objek C ++ global yang disematkan ke alamat komponen perangkat keras (I / O yang dipetakan memori), atau untuk objek statis apa pun yang, karena alasan apa pun, harus berada di alamat tetap.

dorcsssc
sumber
12

Saya telah menggunakannya untuk membuat kelas Variant (yaitu objek yang dapat mewakili nilai tunggal yang dapat menjadi salah satu dari sejumlah jenis yang berbeda).

Jika semua tipe nilai yang didukung oleh kelas Variant adalah tipe POD (mis. Int, float, double, bool) maka gabungan gaya C yang ditandai sudah cukup, tetapi jika Anda ingin beberapa tipe nilai menjadi objek C ++ ( mis. std :: string), fitur C union tidak akan berfungsi, karena tipe data non-POD mungkin tidak dinyatakan sebagai bagian dari union.

Jadi alih-alih saya mengalokasikan array byte yang cukup besar (mis. Sizeof (the_largest_data_type_I_support)) dan menggunakan penempatan baru untuk menginisialisasi objek C ++ yang sesuai di area itu ketika Variant diatur untuk menyimpan nilai jenis itu. (Dan penghapusan penempatan sebelumnya ketika beralih dari tipe data non-POD yang berbeda, tentu saja)

Jeremy Friesner
sumber
Eh, tipe data non-POD dapat dideklarasikan dalam serikat, asalkan Anda memberikan ctor serikat - dan hei - bahwa ctor mungkin akan menggunakan penempatannew untuk menginisialisasi subkelas non-POD. Ref: stackoverflow.com/a/33289972/2757035 Menemukan kembali roda ini menggunakan array byte besar yang sewenang-wenang adalah bagian akrobat yang mengesankan tetapi tampaknya sama sekali tidak perlu, Jadi, apa yang telah saya lewatkan? :)
underscore_d
6
Anda melewatkan semua versi C ++ sebelum C ++ 11, yang dalam banyak kasus masih perlu didukung. :)
Jeremy Friesner
10

Penempatan baru juga sangat berguna saat membuat serial (katakan dengan boost :: serialisasi). Dalam 10 tahun c ++ ini hanya kasus kedua saya membutuhkan penempatan baru untuk (ketiga jika Anda menyertakan wawancara :)).

RichardBruce
sumber
9

Ini juga berguna ketika Anda ingin menginisialisasi ulang struktur global atau yang dialokasikan secara statis.

Cara C lama digunakan memset()untuk mengatur semua elemen ke 0. Anda tidak bisa melakukan itu di C ++ karena vtables dan konstruktor objek kustom.

Jadi saya terkadang menggunakan yang berikut ini

 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.
 }
nimrodm
sumber
1
Tidakkah Anda perlu melakukan penghancuran yang sesuai sebelum menginisialisasi ulang dengan cara itu?
Kepala Geek
[Diedit untuk mengeja] Biasanya - Anda lakukan. Tetapi kadang-kadang, ketika Anda tahu kelas tidak mengalokasikan memori atau sumber daya lainnya (atau Anda membatalkan alokasi mereka secara eksternal - misalnya ketika Anda menggunakan kumpulan memori), Anda dapat menggunakan teknik ini. Itu menjamin bahwa pointer v-table tidak ditimpa. - nimrodm 16 jam yang lalu
nimrodm
1
Bahkan dalam C, menggunakan pengaturan semua bit ke 0 hanya dijamin untuk menghasilkan representasi 0 untuk tipe integral, bukan tipe lainnya (null pointer dapat memiliki representasi bukan nol).
curiousguy
@curiousguy - untuk tipe primitif Anda benar (itu akan membuat program dapat diprediksi yang merupakan keuntungan ketika datang ke debugging). Namun, tipe data C ++ akan menjalankan konstruktornya (di tempat) dan akan diinisialisasi dengan benar.
nimrodm
9

Saya pikir ini belum disorot oleh jawaban apa pun, tetapi contoh bagus dan penggunaan lain untuk penempatan baru adalah untuk mengurangi fragmentasi memori (dengan menggunakan kumpulan memori). Ini sangat berguna dalam sistem yang tersemat dan ketersediaan tinggi. Dalam kasus terakhir ini sangat penting karena untuk sistem yang harus berjalan 24/365 hari sangat penting untuk tidak memiliki fragmentasi. Masalah ini tidak ada hubungannya dengan kebocoran memori.

Bahkan ketika implementasi malloc yang sangat baik digunakan (atau fungsi manajemen memori serupa) sangat sulit untuk berurusan dengan fragmentasi untuk waktu yang lama. Pada titik tertentu jika Anda tidak mengelola dengan cerdas reservasi memori / pelepasan panggilan Anda bisa berakhir dengan banyak celah kecil yang sulit untuk digunakan kembali (ditetapkan untuk reservasi baru). Jadi, salah satu solusi yang digunakan dalam kasus ini adalah menggunakan kolam memori untuk mengalokasikan sebelum menyerahkan memori untuk objek aplikasi. After-ward setiap kali Anda membutuhkan memori untuk beberapa objek, Anda cukup menggunakan penempatan baru untuk membuat objek baru pada memori yang sudah dipesan.

Dengan cara ini, setelah aplikasi Anda mulai, Anda sudah memiliki semua memori yang diperlukan dicadangkan. Semua reservasi / rilis memori baru pergi ke kolam yang dialokasikan (Anda mungkin memiliki beberapa kolam, satu untuk setiap kelas objek yang berbeda). Tidak ada fragmentasi memori yang terjadi dalam kasus ini karena tidak ada celah dan sistem Anda dapat berjalan untuk periode yang sangat lama (bertahun-tahun) tanpa menderita fragmentasi.

Saya melihat ini dalam prakteknya khusus untuk VxWorks RTOS karena sistem alokasi memori standarnya banyak menderita dari fragmentasi. Jadi mengalokasikan memori melalui metode baru / malloc pada dasarnya dilarang dalam proyek. Semua pemesanan memori harus pergi ke kolam memori khusus.

rkachach
sumber
9

Ini sebenarnya jenis yang diperlukan untuk mengimplementasikan segala jenis struktur data yang mengalokasikan lebih banyak memori daripada jumlah minimum yang diperlukan untuk jumlah elemen yang dimasukkan (yaitu, apa pun selain struktur tertaut yang mengalokasikan satu node pada suatu waktu).

Kontainer take suka unordered_map, vectoratau deque. Ini semua mengalokasikan lebih banyak memori daripada yang diperlukan minimal untuk elemen yang Anda masukkan sejauh ini untuk menghindari membutuhkan alokasi tumpukan untuk setiap penyisipan tunggal. Mari kita gunakan vectorsebagai contoh paling sederhana.

Saat kamu melakukan:

vector<Foo> vec;

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

... itu tidak benar-benar membangun seribu Foos. Itu hanya mengalokasikan / cadangan memori untuk mereka. Jika vectortidak menggunakan penempatan baru di sini, itu akan membangun-default di Foossemua tempat serta harus memanggil destruktor mereka bahkan untuk elemen yang bahkan tidak pernah Anda masukkan di tempat pertama.

Alokasi! = Konstruksi, Membebaskan! = Penghancuran

Secara umum, untuk menerapkan banyak struktur data seperti di atas, Anda tidak dapat memperlakukan alokasi memori dan membangun elemen sebagai satu hal yang tidak dapat dibagi, dan Anda juga tidak dapat memperlakukan memori bebas dan menghancurkan elemen sebagai satu hal yang tidak dapat dibagi.

Harus ada pemisahan antara ide-ide ini untuk menghindari konstruktor dan penghancur yang berlebihan yang tidak perlu ke kiri dan kanan, dan itulah sebabnya perpustakaan standar memisahkan ide std::allocator(yang tidak membangun atau menghancurkan elemen ketika mengalokasikan / membebaskan memori *) dari kontainer yang menggunakannya yang secara manual membangun elemen menggunakan penempatan yang baru dan secara manual menghancurkan elemen menggunakan doa eksplisit dari destruktor.

  • Aku benci desain std::allocatortapi itu subjek yang berbeda, aku tidak akan mengomel. :-D

Jadi, bagaimanapun, saya cenderung sering menggunakannya karena saya telah menulis sejumlah kontainer standar C ++ yang sesuai dengan tujuan umum yang tidak dapat dibangun dalam hal yang sudah ada. Termasuk di antaranya adalah implementasi vektor kecil yang saya buat beberapa dekade yang lalu untuk menghindari alokasi tumpukan dalam kasus-kasus umum, dan trie yang hemat memori (tidak mengalokasikan satu simpul pada satu waktu). Dalam kedua kasus saya tidak bisa benar-benar menerapkannya menggunakan wadah yang ada, jadi saya harus menggunakannyaplacement new untuk menghindari konstruktor dan destruktor berlebihan pada hal-hal yang tidak perlu kiri dan kanan.

Tentu saja jika Anda pernah bekerja dengan pengalokasi khusus untuk mengalokasikan objek secara individual, seperti daftar gratis, maka Anda umumnya juga ingin menggunakan placement new, seperti ini (contoh dasar yang tidak repot dengan pengecualian-keselamatan atau RAII):

Foo* foo = new(free_list.allocate()) Foo(...);
...
foo->~Foo();
free_list.free(foo);
Energi Naga
sumber
8

Berguna jika Anda membangun kernel - di mana Anda menempatkan kode kernel yang Anda baca dari disk atau pagetable? Anda harus tahu ke mana harus melompat.

Atau dalam keadaan lain, sangat jarang seperti ketika Anda memiliki banyak ruang yang dialokasikan dan ingin menempatkan beberapa struktur di belakang satu sama lain. Mereka dapat dikemas dengan cara ini tanpa perlu offset () operator. Ada trik lain untuk itu juga.

Saya juga percaya beberapa implementasi STL menggunakan penempatan baru, seperti std :: vector. Mereka mengalokasikan ruang untuk 2 elemen seperti itu dan tidak perlu selalu realokasi.

mstrobl
sumber
Mengurangi alokasi memori adalah salah satu alasan utama untuk menggunakannya, serta "trik" seperti pemuatan objek off disk
lefticus
Saya tidak tahu ada kernel yang ditulis dalam C ++; sebagian besar kernel ditulis dalam C. lurus
Adam Rosenfield
8
Sistem operasi yang saya pelajari dasar-dasarnya OS ditulis dalam C ++: sweb.sourceforge.net
mstrobl
8

Ini digunakan oleh std::vector<>karena std::vector<>biasanya mengalokasikan lebih banyak memori daripada yang ada objectsdi vector<>.

Andreas Magnusson
sumber
7

Saya telah menggunakannya untuk menyimpan objek dengan file yang dipetakan memori.
Contoh spesifik adalah database gambar yang memproses banyak gambar besar (lebih dari yang bisa disimpan dalam memori).

Martin Beckett
sumber
7

Saya telah melihatnya digunakan sebagai sedikit peretasan kinerja untuk penunjuk "tipe dinamis" (di bagian "Di Balik Terpal"):

Tapi di sini adalah trik rumit yang saya gunakan untuk mendapatkan kinerja cepat untuk tipe kecil: jika nilai yang dipegang dapat masuk dalam kekosongan *, saya tidak benar-benar repot mengalokasikan objek baru, saya memaksanya ke dalam pointer itu sendiri menggunakan penempatan baru .

Max Lybbert
sumber
Apa artinya jika nilai yang dipegang dapat masuk dalam kekosongan * artinya? Selalu memungkinkan untuk menetapkan jenis pointer apa pun untuk membatalkan *. Bisakah Anda tunjukkan pada kami beberapa contoh?
anurag86
@ anurag86: Di mesin 64 bit saya, a void*membutuhkan 8 byte. Agak konyol menunjuk delapan byte void*pada satu byte bool. Tetapi sepenuhnya mungkin untuk benar-benar overlay boolpada void*, seperti a union { bool b; void* v }. Anda perlu cara untuk mengetahui bahwa benda yang Anda panggil void*sebenarnya adalah bool(atau a short, atau a float, dll.). Artikel yang saya tautkan menjelaskan cara melakukannya. Dan, untuk menjawab pertanyaan awal, penempatan newadalah fitur yang digunakan untuk membuat bool(atau jenis lain) di mana a void*diharapkan, (gips digunakan untuk nanti mendapatkan / memodifikasi nilai).
Max Lybbert
@ anurag86: Ini bukan hal yang sama, tetapi Anda mungkin tertarik dengan pointer yang ditandai ( en.wikipedia.org/wiki/Tagged_pointer ).
Max Lybbert
6

Saya menggunakannya untuk membuat objek berdasarkan memori yang berisi pesan yang diterima dari jaringan.

Steve Fallows
sumber
5

Umumnya, penempatan baru digunakan untuk menghilangkan biaya alokasi 'normal baru'.

Skenario lain di mana saya menggunakannya adalah tempat di mana saya ingin memiliki akses ke pointer ke objek yang masih akan dibangun, untuk mengimplementasikan per-dokumen tunggal.

xtofl
sumber
4

Satu tempat saya bertemu adalah dalam wadah yang mengalokasikan buffer yang berdekatan dan kemudian mengisinya dengan benda-benda yang diperlukan. Seperti disebutkan, std :: vector mungkin melakukan ini, dan saya tahu beberapa versi MFC CArray dan / atau CList melakukan ini (karena di situlah saya pertama kali berlari melewatinya). Metode alokasi berlebih buffer adalah optimasi yang sangat berguna, dan penempatan yang baru cukup satu-satunya cara untuk membangun objek dalam skenario itu. Ini juga kadang-kadang digunakan untuk membangun objek di blok memori yang dialokasikan di luar kode langsung Anda.

Saya telah menggunakannya dalam kapasitas yang sama, meskipun tidak sering muncul. Ini adalah alat yang berguna untuk kotak alat C ++.

Nick
sumber
4

Mesin skrip dapat menggunakannya di antarmuka asli untuk mengalokasikan objek asli dari skrip. Lihat Angelscript (www.angelcode.com/angelscript) untuk contohnya.

Raindog
sumber
3

Lihat file fp.h dalam proyek xll di http://xll.codeplex.com. Ini memecahkan masalah "kekejaman yang tidak beralasan dengan kompiler" untuk array yang suka membawa dimensi mereka dengan mereka.

typedef struct _FP
{
    unsigned short int rows;
    unsigned short int columns;
    double array[1];        /* Actually, array[rows][columns] */
} FP;
Keith A. Lewis
sumber
2

Berikut ini adalah penggunaan pembunuh untuk konstruktor C ++ di tempat: menyelaraskan ke baris cache, serta kekuatan 2 batas lainnya. Berikut ini adalah algoritma penyelarasan pointer ultra-cepat untuk kekuatan 2 batas dengan 5 atau kurang instruksi satu siklus :

/* 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 ();

Sekarang bukankah itu hanya membuat senyum di wajah Anda (:-). Saya ♥♥♥ C ++ 1x


sumber