Có những cách sử dụng nào cho vị trí mới của người mới?


411

Có ai ở đây đã từng sử dụng "vị trí mới" của C ++ chưa? Nếu vậy, để làm gì? Đối với tôi có vẻ như nó chỉ hữu ích trên phần cứng được ánh xạ bộ nhớ.


14
Đây chỉ là thông tin mà tôi đang tìm kiếm, để gọi các nhà xây dựng đối tượng trên các nhóm bộ nhớ được phân bổ. (Hy vọng những từ khóa này sẽ giúp ai đó dễ dàng tìm thấy hơn trong tương lai).
diễn Bob

2
Nó được sử dụng trong bài viết Wikipedia C ++ 11 trong hàm tạo của liên minh.
Goodbye

@Hello Goodbye, thú vị! Trong bài viết bạn đã liên kết, tại sao bạn không thể làm p = ptvà sử dụng toán tử gán Pointthay vì làm new(&p) Point(pt)? Tôi tự hỏi về sự khác biệt giữa hai. operator=Cái trước sẽ gọi vào Point, trong khi cái sau gọi hàm tạo sao chép của Point? nhưng tôi vẫn không rõ tại sao cái này tốt hơn cái kia.
Andrei-Niculae Petre

@ Andrei-NiculaePetre Tôi chưa sử dụng vị trí mới, nhưng tôi đoán bạn nên sử dụng nó cùng với trình tạo bản sao, nếu bạn hiện không có đối tượng của lớp đó, nếu không bạn nên sử dụng toán tử gán sao chép. Trừ khi lớp học là tầm thường; sau đó nó không quan trọng bạn sử dụng cái nào trong số họ. Điều tương tự cũng xảy ra đối với sự phá hủy của đối tượng. Không xử lý việc này đúng cách đối với các lớp không tầm thường rất có thể dẫn đến hành vi lạ và thậm chí có thể gây ra hành vi không xác định trong một số tình huống.
HelloGoodbye

@ Andrei-NiculaePetre Trên thực tế, tôi thấy ví dụ trong bài viết trên Wikipedia khá tệ, vì nó chỉ cho rằng không có đối tượng trước tồn tại và họ cần xây dựng một đối tượng. Đây không phải là trường hợp nếu U::operator=vừa được gọi.
HelloGoodbye

Câu trả lời:


365

Vị trí mới cho phép bạn xây dựng một đối tượng trong bộ nhớ đã được phân bổ.

Bạn có thể muốn làm điều này để tối ưu hóa khi bạn cần xây dựng nhiều phiên bản của một đối tượng và nhanh hơn là không phân bổ lại bộ nhớ mỗi khi bạn cần một thể hiện mới. Thay vào đó, có thể hiệu quả hơn khi thực hiện một phân bổ duy nhất cho một đoạn bộ nhớ có thể chứa nhiều đối tượng, mặc dù bạn không muốn sử dụng tất cả chúng cùng một lúc.

DevX đưa ra một ví dụ tốt :

Standard C ++ cũng hỗ trợ toán tử vị trí mới, cấu trúc một đối tượng trên bộ đệm được phân bổ trước. Điều này hữu ích khi xây dựng nhóm bộ nhớ, bộ thu gom rác hoặc đơn giản là khi hiệu suất và an toàn ngoại lệ là tối quan trọng (không có nguy cơ thất bại phân bổ do bộ nhớ đã được phân bổ và việc xây dựng một đối tượng trên bộ đệm được phân bổ trước mất ít thời gian hơn) :

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

Bạn cũng có thể muốn chắc chắn rằng không thể có lỗi phân bổ tại một phần nhất định của mã quan trọng (ví dụ: trong mã được thực hiện bởi máy điều hòa nhịp tim). Trong trường hợp đó, bạn sẽ muốn phân bổ bộ nhớ sớm hơn, sau đó sử dụng vị trí mới trong phần quan trọng.

Giao dịch trong vị trí mới

Bạn không nên phân bổ mọi đối tượng đang sử dụng bộ nhớ đệm. Thay vào đó, bạn chỉ nên xóa [] bộ đệm ban đầu. Sau đó, bạn sẽ phải gọi các hàm hủy của các lớp của mình một cách thủ công. Để có gợi ý hay về vấn đề này, vui lòng xem Câu hỏi thường gặp của Stroustrup về: Có "xóa vị trí" không?


54
Nó không bị phản đối vì bạn cần tính năng này để triển khai các đối tượng container (như vector) một cách hiệu quả. Nếu bạn không xây dựng container của riêng mình, bạn không cần sử dụng tính năng này.
Martin York

26
Điều cũng rất quan trọng cần nhớ là #include <memory>, nếu không, bạn có thể gặp phải một số cơn đau đầu khủng khiếp ở một số nền tảng không tự động nhận ra vị trí mới
Ramon Zarazua B.

22
Nghiêm túc, đó là hành vi không xác định để gọi bộ đệm delete[]ban đầu char. Sử dụng vị trí newđã kết thúc vòng đời của các charđối tượng ban đầu bằng cách sử dụng lại bộ nhớ của chúng. Nếu bây giờ bạn gọi delete[] bufloại động của (các) đối tượng được trỏ đến không còn phù hợp với loại tĩnh của chúng để bạn có hành vi không xác định. Nó phù hợp hơn để sử dụng operator new/ operator deleteđể phân bổ bộ nhớ thô dự định sử dụng theo vị trí new.
CB Bailey

31
Tôi chắc chắn sẽ bỏ qua việc sử dụng đống trong máy tạo nhịp tim :-)
Eli Bendersky

15
@RamonZarazua Tiêu đề sai, đó là #include <new>.
bit2shift

63

Chúng tôi sử dụng nó với nhóm bộ nhớ tùy chỉnh. Chỉ là một bản phác thảo:

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

Giờ đây, bạn có thể phân cụm các đối tượng lại với nhau trong một trường bộ nhớ duy nhất, chọn một bộ cấp phát rất nhanh nhưng không phân bổ, sử dụng ánh xạ bộ nhớ và bất kỳ ngữ nghĩa nào khác mà bạn muốn áp đặt bằng cách chọn nhóm và chuyển nó làm đối số cho vị trí của đối tượng nhà điều hành mới.


1
Vâng. Chúng tôi khá thông minh về điều đó, nhưng nó lạc đề cho câu hỏi này.
Don Wakefield

2
@jdkoftinoff bạn có liên kết nào đến một mẫu mã thực tế không? có vẻ khá thú vị đối với tôi
Victor

@DonWakefield Làm thế nào để bạn xử lý sự liên kết trong nhóm này? Bạn không nên vượt qua sự liên kết như là một đối số đến allocate()một nơi nào đó?
Mikhail Vasilyev

1
@MikhailVasilyev, trong một triển khai thực tế, tất nhiên bạn sẽ xử lý việc đó. Mã ví dụ duy nhất.
Don Wakefield

Nếu vị trí là một địa chỉ không hợp lệ, hãy nói 0x0?
Charlie

51

Nó hữu ích nếu bạn muốn tách phân bổ khỏi khởi tạo. STL sử dụng vị trí mới để tạo các phần tử container.


35

Tôi đã sử dụng nó trong lập trình thời gian thực. Chúng tôi thường không muốn thực hiện bất kỳ phân bổ động (hoặc thỏa thuận) nào sau khi hệ thống khởi động, bởi vì không có gì đảm bảo sẽ mất bao lâu.

Những gì tôi có thể làm là phân bổ một khối lớn bộ nhớ (đủ lớn để chứa bất kỳ số lượng nào mà lớp có thể yêu cầu). Sau đó, một khi tôi tìm ra cách chạy để xây dựng mọi thứ, vị trí mới có thể được sử dụng để xây dựng các đối tượng ngay tại nơi tôi muốn. Một tình huống tôi biết tôi đã sử dụng nó là để giúp tạo ra một bộ đệm tròn không đồng nhất .

Nó chắc chắn không dành cho người yếu tim, nhưng đó là lý do tại sao họ tạo ra cú pháp cho nó một cách sởn gai ốc.


Xin chào TED, bạn có thể vui lòng chia sẻ thêm về giải pháp bạn có. Tôi đang suy nghĩ về một giải pháp được phân bổ trước nhưng không có nhiều tiến bộ. Cảm ơn bạn trước!
Việt Nam

1
Chà, mã đệm tròn hetrogenious thực sự là phần khó khăn để làm đúng. Các palced mới trông hơi ghê, nhưng bằng cách so sánh nó không có rắc rối nào cả.
TED

26

Tôi đã sử dụng nó để xây dựng các đối tượng được phân bổ trên ngăn xếp thông qua alloca ().

không biết xấu hổ cắm: tôi viết blog về nó ở đây .


bài viết thú vị, nhưng tôi không chắc tôi hiểu lợi thế của việc sử dụng này boost::array. Bạn có thể mở rộng về điều đó một chút?
GrahamS

boost :: mảng yêu cầu kích thước của mảng là hằng số thời gian biên dịch. Điều này không có giới hạn đó.
Ferruccio

2
@Ferruccio Điều này khá tuyệt, tôi đã nhận thấy rằng macro của bạn hơi không an toàn, cụ thể là kích thước có thể là một ngoại lệ. Nếu x + 1 được truyền vào chẳng hạn, bạn sẽ mở rộng nó thành sizeof (loại) * x + 1 sẽ không chính xác. Bạn cần đóng khung macro của bạn để làm cho nó an toàn hơn.
Ngày

Sử dụng với alloca có vẻ nguy hiểm đối với tôi nếu một ngoại lệ được ném ra khi bạn phải gọi các hàm hủy trên tất cả các đối tượng của bạn.
CashCow

14

Đầu Geek: BINGO! Bạn đã hoàn toàn hiểu được - đó chính xác là những gì nó hoàn hảo. Trong nhiều môi trường nhúng, các ràng buộc bên ngoài và / hoặc kịch bản sử dụng tổng thể buộc lập trình viên tách biệt việc phân bổ một đối tượng khỏi khởi tạo. Được gộp lại với nhau, C ++ gọi đây là "khởi tạo"; nhưng bất cứ khi nào hành động của nhà xây dựng phải được gọi một cách rõ ràng mà KHÔNG phân bổ động hoặc tự động, vị trí mới là cách để thực hiện. Đây cũng là cách hoàn hảo để xác định vị trí của một đối tượng C ++ toàn cầu được ghim vào địa chỉ của một thành phần phần cứng (I / O được ánh xạ bộ nhớ) hoặc cho bất kỳ đối tượng tĩnh nào, vì bất kỳ lý do gì, phải nằm ở một địa chỉ cố định.


12

Tôi đã sử dụng nó để tạo một lớp Biến thể (tức là một đối tượng có thể biểu thị một giá trị duy nhất có thể là một trong một số loại khác nhau).

Nếu tất cả các loại giá trị được hỗ trợ bởi lớp Biến thể là các loại POD (ví dụ: int, float, double, bool) thì liên kết kiểu C được gắn thẻ là đủ, nhưng nếu bạn muốn một số loại giá trị là đối tượng C ++ ( ví dụ: std :: string), tính năng kết hợp C sẽ không được thực hiện, vì các kiểu dữ liệu không phải POD có thể không được khai báo như là một phần của liên minh.

Vì vậy, thay vào đó tôi phân bổ một mảng byte đủ lớn (ví dụ sizeof (the_largest_data_type_I_support)) và sử dụng vị trí mới để khởi tạo đối tượng C ++ thích hợp trong khu vực đó khi Biến thể được đặt để giữ giá trị của loại đó. (Tất nhiên, và xóa vị trí trước khi chuyển khỏi loại dữ liệu không phải POD khác), tất nhiên)


Erm, các kiểu dữ liệu không phải POD có thể được khai báo trong một liên minh, miễn là bạn cung cấp một ctor union - và hey - ctor đó có thể sẽ sử dụng vị trínew để khởi tạo lớp con không phải POD của nó. Tham khảo: stackoverflow.com/a/33289972/2757035 Phát minh lại bánh xe này bằng cách sử dụng một mảng byte lớn tùy ý là một phần nhào lộn ấn tượng nhưng dường như hoàn toàn không cần thiết, vậy, tôi đã bỏ lỡ điều gì? :)
gạch dưới

6
Bạn đã bỏ lỡ tất cả các phiên bản của C ++ trước C ++ 11, trong nhiều trường hợp vẫn cần phải được hỗ trợ. :)
Jeremy Friesner

10

Vị trí mới cũng rất hữu ích khi xê-ri hóa (nói với boost :: serialization). Trong 10 năm của c ++, đây chỉ là trường hợp thứ hai tôi cần vị trí mới cho (thứ ba nếu bạn bao gồm các cuộc phỏng vấn :)).


9

Nó cũng hữu ích khi bạn muốn khởi tạo lại các cấu trúc toàn cầu hoặc được phân bổ tĩnh.

Cách C cũ đã sử dụng memset()để đặt tất cả các phần tử thành 0. Bạn không thể làm điều đó trong C ++ do vtables và các hàm tạo đối tượng tùy chỉnh.

Vì vậy, đôi khi tôi sử dụng như sau

 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
Bạn sẽ không cần phải thực hiện một sự hủy diệt tương ứng trước khi khởi tạo lại nó theo cách đó chứ?
Head Geek

[Chỉnh sửa chính tả] Thông thường - bạn làm. Nhưng đôi khi, khi bạn biết lớp không phân bổ bộ nhớ hoặc các tài nguyên khác (hoặc bạn đã giải phóng chúng ra bên ngoài - ví dụ như khi bạn sử dụng nhóm bộ nhớ), bạn có thể sử dụng kỹ thuật này. Nó đảm bảo rằng các con trỏ bảng v không bị ghi đè. - nimrodm 16 giờ trước
nimrodm

1
Ngay cả trong C, việc sử dụng cài đặt tất cả các bit thành 0 chỉ được đảm bảo để tạo ra một đại diện bằng 0 cho các loại tích phân, không phải các loại khác (con trỏ null có thể có biểu diễn khác không).
tò mò

@cquilguy - đối với các kiểu nguyên thủy bạn đúng (nó sẽ làm cho chương trình có thể dự đoán được, đây là một lợi thế khi gỡ lỗi). Tuy nhiên, kiểu dữ liệu C ++ sẽ chạy hàm tạo của chúng (tại chỗ) và sẽ được khởi tạo đúng cách.
nimrodm

9

Tôi nghĩ rằng điều này chưa được làm nổi bật bởi bất kỳ câu trả lời nào, nhưng một ví dụ hay và cách sử dụng khác cho vị trí mới là giảm sự phân mảnh bộ nhớ (bằng cách sử dụng nhóm bộ nhớ). Điều này đặc biệt hữu ích trong các hệ thống nhúng và tính sẵn sàng cao. Trong trường hợp cuối cùng này, nó đặc biệt quan trọng bởi vì đối với một hệ thống phải chạy 24/365 ngày, điều rất quan trọng là không có sự phân mảnh. Vấn đề này không liên quan gì đến rò rỉ bộ nhớ.

Ngay cả khi triển khai malloc rất tốt (hoặc chức năng quản lý bộ nhớ tương tự), rất khó để xử lý phân mảnh trong một thời gian dài. Tại một số điểm, nếu bạn không quản lý khéo léo các cuộc gọi đặt chỗ / giải phóng bộ nhớ, bạn có thể kết thúc với rất nhiều khoảng trống nhỏ khó sử dụng lại (gán cho các đặt chỗ mới). Vì vậy, một trong những giải pháp được sử dụng trong trường hợp này là sử dụng nhóm bộ nhớ để phân bổ trước khi trao bộ nhớ cho các đối tượng ứng dụng. Sau mỗi lần bạn cần bộ nhớ cho một số đối tượng, bạn chỉ cần sử dụng vị trí mới để tạo một đối tượng mới trên bộ nhớ đã được bảo lưu.

Bằng cách này, khi ứng dụng của bạn khởi động, bạn đã có tất cả bộ nhớ cần thiết. Tất cả các dự trữ / giải phóng bộ nhớ mới đều được chuyển đến các nhóm được phân bổ (bạn có thể có một số nhóm, một nhóm cho mỗi lớp đối tượng khác nhau). Không có sự phân mảnh bộ nhớ xảy ra trong trường hợp này vì sẽ không có khoảng trống và hệ thống của bạn có thể chạy trong thời gian rất dài (năm) mà không bị phân mảnh.

Tôi đã thấy điều này trong thực tế đặc biệt cho VxWorks RTOS vì hệ thống cấp phát bộ nhớ mặc định của nó chịu rất nhiều sự phân mảnh. Vì vậy, phân bổ bộ nhớ thông qua phương pháp mới / malloc tiêu chuẩn về cơ bản đã bị cấm trong dự án. Tất cả các đặt phòng bộ nhớ nên đi đến một bộ nhớ chuyên dụng.


9

Đó thực sự là loại bắt buộc để thực hiện bất kỳ loại cấu trúc dữ liệu nào phân bổ nhiều bộ nhớ hơn mức yêu cầu tối thiểu cho số lượng phần tử được chèn (nghĩa là, bất kỳ thứ gì khác ngoài cấu trúc được liên kết phân bổ một nút tại một thời điểm).

Container mất thích unordered_map, vectorhoặc deque. Tất cả đều phân bổ nhiều bộ nhớ hơn mức yêu cầu tối thiểu cho các yếu tố bạn đã chèn cho đến nay để tránh yêu cầu phân bổ heap cho mỗi lần chèn. Hãy sử dụng vectornhư một ví dụ đơn giản nhất.

Khi bạn làm:

vector<Foo> vec;

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

... điều đó không thực sự tạo ra một ngàn Foos. Nó chỉ đơn giản là phân bổ / dự trữ bộ nhớ cho họ. Nếu vectorkhông sử dụng vị trí mới ở đây, nó sẽ được mặc định - xây dựng ở Fooskhắp mọi nơi cũng như phải gọi các hàm hủy của chúng ngay cả đối với các phần tử mà bạn chưa từng chèn vào vị trí đầu tiên.

Phân bổ! = Xây dựng, Giải phóng! = Phá hủy

Nói chung, để thực hiện nhiều cấu trúc dữ liệu như trên, bạn không thể coi việc phân bổ bộ nhớ và xây dựng các phần tử là một thứ không thể tách rời và bạn cũng không thể coi việc giải phóng bộ nhớ và phá hủy các phần tử là một thứ không thể chia tách.

Phải có một sự tách biệt giữa các ý tưởng này để tránh việc gọi các nhà xây dựng và phá hủy một cách không cần thiết trái và phải, và đó là lý do tại sao thư viện tiêu chuẩn tách biệt ý tưởng std::allocator(không xây dựng hoặc phá hủy các phần tử khi phân bổ / giải phóng bộ nhớ *) các thùng chứa sử dụng nó để xây dựng các phần tử theo cách thủ công bằng cách sử dụng các phần tử mới và hủy thủ công bằng cách sử dụng các lệnh hủy rõ ràng.

  • Tôi ghét thiết kế của std::allocatornhưng đó là một chủ đề khác tôi sẽ tránh nói. : -D

Vì vậy, dù sao đi nữa, tôi có xu hướng sử dụng nó rất nhiều vì tôi đã viết một số bộ chứa C ++ tuân thủ tiêu chuẩn cho mục đích chung không thể được xây dựng theo các cái hiện có. Bao gồm trong số đó là một triển khai vectơ nhỏ mà tôi đã xây dựng vài thập kỷ trước để tránh phân bổ heap trong các trường hợp phổ biến và bộ ba hiệu quả bộ nhớ (không phân bổ một nút tại một thời điểm). Trong cả hai trường hợp, tôi không thể thực sự sử dụng chúng bằng cách sử dụng các container hiện có, và vì vậy tôi phải sử dụng placement newđể tránh việc gọi các nhà xây dựng và phá hủy một cách không cần thiết trên những thứ không cần thiết trái và phải.

Đương nhiên, nếu bạn từng làm việc với các bộ cấp phát tùy chỉnh để phân bổ các đối tượng riêng lẻ, như một danh sách miễn phí, thì bạn cũng thường muốn sử dụng placement new, như thế này (ví dụ cơ bản không liên quan đến an toàn ngoại lệ hoặc RAII):

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

8

Nó rất hữu ích nếu bạn đang xây dựng kernel - nơi bạn đặt mã kernel mà bạn đọc từ đĩa hoặc có thể phân trang? Bạn cần biết nơi để nhảy đến.

Hoặc trong các trường hợp khác, rất hiếm khi bạn có vô số phòng được phân bổ và muốn đặt một vài cấu trúc phía sau nhau. Chúng có thể được đóng gói theo cách này mà không cần toán tử offset (). Có những thủ thuật khác cho điều đó quá, mặc dù.

Tôi cũng tin rằng một số triển khai STL sử dụng vị trí mới, như std :: vector. Họ phân bổ phòng cho 2 ^ n yếu tố theo cách đó và không cần phải luôn luôn phân bổ lại.


Giảm phân bổ bộ nhớ là một lý do chính để sử dụng nó, cũng như các "thủ thuật" như tải các đối tượng ra khỏi đĩa
lefticus

Tôi không biết bất kỳ hạt nhân nào được viết bằng C ++; hầu hết các hạt nhân được viết thẳng C.
Adam Rosenfield

8
Hệ điều hành mà tôi đã học những điều cơ bản về hệ điều hành được viết bằng C ++: sweb.sourceforge.net
mstrobl

8

Nó được sử dụng bởi std::vector<>std::vector<>thường phân bổ nhiều bộ nhớ hơn so với objectstrong vector<>.


7

Tôi đã sử dụng nó để lưu trữ các đối tượng với các tập tin ánh xạ bộ nhớ.
Ví dụ cụ thể là một cơ sở dữ liệu hình ảnh xử lý số lượng lớn hình ảnh lớn (nhiều hơn có thể vừa với bộ nhớ).


7

Tôi đã thấy nó được sử dụng như một hack hiệu suất nhẹ cho một con trỏ "kiểu động" (trong phần "Under the Hood"):

Nhưng đây là mẹo khó mà tôi đã sử dụng để có hiệu suất nhanh cho các loại nhỏ: nếu giá trị được giữ có thể nằm trong khoảng trống *, tôi thực sự không bận tâm đến việc phân bổ một đối tượng mới, tôi buộc nó vào chính con trỏ bằng cách sử dụng vị trí mới .


Điều gì xảy ra nếu giá trị được giữ có thể nằm trong khoảng trống * có nghĩa là gì? Luôn luôn có thể gán bất kỳ loại con trỏ nào vào void *. Bạn có thể vui lòng cho chúng tôi xem một số ví dụ?
anurag86

@ anurag86: Trên máy 64 bit của tôi, void*mất 8 byte. Thật là hơi ngớ ngẩn khi chỉ tám byte void*ở một byte bool. Nhưng nó hoàn toàn có thể thực sự che phủ booltrên void*, giống như một union { bool b; void* v }. Bạn cần một số cách để biết rằng thứ bạn gọi void*là thực sự là một bool(hoặc a short, hoặc a float, v.v.). Bài viết tôi liên kết để mô tả làm thế nào để làm điều đó. Và, để trả lời câu hỏi ban đầu, vị trí newlà tính năng được sử dụng để tạo bool(hoặc loại khác) trong đó a void*được mong đợi, (phôi được sử dụng để nhận / sửa đổi giá trị sau này).
Max Lybbert

@ anurag86: Đó không phải là điều tương tự, nhưng bạn có thể quan tâm đến các con trỏ được gắn thẻ ( en.wikipedia.org/wiki/Tagged_pulum ).
Max Lybbert

6

Tôi đã sử dụng nó để tạo các đối tượng dựa trên bộ nhớ chứa các tin nhắn nhận được từ mạng.


5

Nói chung, vị trí mới được sử dụng để loại bỏ chi phí phân bổ của một 'mới bình thường'.

Một kịch bản khác mà tôi đã sử dụng nó là một nơi mà tôi muốn có quyền truy cập vào con trỏ tới một đối tượng vẫn sẽ được xây dựng, để thực hiện một singleton trên mỗi tài liệu.



4

Một nơi tôi chạy ngang qua nó là trong các thùng chứa phân bổ bộ đệm liền kề và sau đó lấp đầy nó với các đối tượng theo yêu cầu. Như đã đề cập, std :: vector có thể làm điều này và tôi biết một số phiên bản của MFC CArray và / hoặc CList đã làm điều này (vì đó là lần đầu tiên tôi chạy qua nó). Phương pháp phân bổ quá mức bộ đệm là một tối ưu hóa rất hữu ích và vị trí mới là cách duy nhất để xây dựng các đối tượng trong kịch bản đó. Đôi khi nó cũng được sử dụng để xây dựng các đối tượng trong các khối bộ nhớ được phân bổ bên ngoài mã trực tiếp của bạn.

Tôi đã sử dụng nó trong một khả năng tương tự, mặc dù nó không xuất hiện thường xuyên. Tuy nhiên, đây là một công cụ hữu ích cho hộp công cụ C ++.


4

Các công cụ script có thể sử dụng nó trong giao diện gốc để phân bổ các đối tượng gốc từ các script. Xem Angelscript (www.angelcode.com/angelscript) để biết ví dụ.


3

Xem tệp fp.h trong dự án xll tại http://xll.codeplex.com Nó giải quyết vấn đề "không đáng tin cậy với trình biên dịch" cho các mảng muốn mang theo kích thước của chúng xung quanh chúng.

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

2

Dưới đây là cách sử dụng sát thủ cho hàm tạo tại chỗ C ++: căn chỉnh theo một dòng bộ đệm, cũng như các quyền hạn khác của 2 ranh giới. Dưới đây là thuật toán căn chỉnh con trỏ cực nhanh của tôi với bất kỳ sức mạnh nào của 2 ranh giới với 5 hoặc ít hơn các hướng dẫn chu kỳ đơn :

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

Bây giờ không chỉ là đặt một nụ cười trên khuôn mặt của bạn (:-). Tôi ♥♥♥ C ++ 1x

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.