2008-08-14 34 views
22

Có ai biết làm thế nào tôi có thể, trong mã C++ độc lập nền tảng ngăn chặn một đối tượng được tạo ra trên heap? Đó là, cho một lớp "Foo", tôi muốn ngăn chặn người dùng thực hiện điều này:Làm thế nào để ngăn chặn một đối tượng được tạo ra trên heap?

Foo *ptr = new Foo; 

và chỉ cho phép họ làm điều này:

Foo myfooObject; 

Có ai có bất kỳ ý tưởng?

Chúc mừng,

+2

Tại sao bạn muốn thực hiện việc này? –

+0

Điều ngược lại, điều này cũng có thể thú vị đối với người đọc: http://stackoverflow.com/questions/124880/is-it-possible-to-prevent-stack-allocation-of-an-object-and-only-allow- nó-to-be – kevinarpe

Trả lời

24

Nick's answer là một điểm khởi đầu tốt, nhưng không đầy đủ, khi bạn thực sự cần phải quá tải:

private: 
    void* operator new(size_t);   // standard new 
    void* operator new(size_t, void*); // placement new 
    void* operator new[](size_t);  // array new 
    void* operator new[](size_t, void*); // placement array new 

(thực hành tốt mã hóa sẽ đề nghị bạn cũng nên quá tải xóa và xóa nhà khai thác [] - Tôi sẽ, nhưng vì họ sẽ không có được gọi là nó không phải là thực sự cần thiết.)

Pauldoo cũng là đúng rằng điều này không tồn tại tập hợp trên Foo, mặc dù nó không tồn tại kế thừa từ Foo. Bạn có thể làm một số ma thuật lập trình meta template để HELP ngăn chặn điều này, nhưng nó sẽ không được miễn nhiễm với "người dùng xấu" và do đó có lẽ không đáng để biến chứng. Tài liệu về cách nó nên được sử dụng, và xem xét mã để đảm bảo nó được sử dụng đúng cách, là cách duy nhất ~ 100%.

+1

Một nhà xây dựng tư nhân có được kết hợp với phương thức nhà máy tĩnh công khai (trả về theo giá trị) thực hiện giống nhau không? – kevinarpe

+1

@ kevinarpe Nó phụ thuộc vào cách chúng ta đang đọc câu hỏi. Mã chính xác 'Foo myfooObject;' từ câu hỏi sẽ không biên dịch nếu bạn đã làm điều đó. Điều đó nói rằng tôi thích một cách tiếp cận giống như những gì bạn đang đề xuất, nếu tôi đang cố gắng để kiểm soát cách các đối tượng được tạo ra. –

-1

Bạn có thể khai báo một chức năng gọi là "điều hành mới" bên trong lớp Foo mà sẽ ngăn chặn việc truy cập vào các hình thức bình thường mới.

Đây có phải là loại hành vi bạn muốn không?

7

Bạn có thể quá tải mới cho Foo và đặt ở chế độ riêng tư. Điều này có nghĩa là trình biên dịch sẽ rên rỉ ... trừ khi bạn đang tạo một thể hiện của Foo trên heap từ bên trong Foo. Để nắm bắt trường hợp này, bạn có thể chỉ đơn giản là không viết phương thức mới của Foo và sau đó trình liên kết sẽ rên rỉ về các ký hiệu không xác định.

class Foo { 
private: 
    void* operator new(size_t size); 
}; 

PS. Vâng, tôi biết điều này có thể được phá vỡ dễ dàng. Tôi thực sự không giới thiệu nó - Tôi nghĩ đó là một ý tưởng tồi - tôi chỉ trả lời câu hỏi này! ;-)

-1

Không chắc chắn nếu điều này cung cấp bất kỳ cơ hội thời gian biên dịch nào, nhưng bạn đã xem xét quá tải toán tử 'mới' cho lớp học của mình chưa?

6

Tôi không biết làm thế nào để làm điều đó đáng tin cậy và một cách cầm tay .. nhưng ..

Nếu đối tượng là trên stack sau đó bạn có thể có thể khẳng định trong constructor rằng giá trị của ' này 'luôn luôn gần với con trỏ ngăn xếp. Có một cơ hội tốt mà đối tượng sẽ được trên stack nếu đây là trường hợp.

Tôi tin rằng không phải tất cả các nền tảng thực hiện ngăn xếp của họ theo cùng một hướng, vì vậy bạn có thể muốn làm một bài kiểm tra một lần khi ứng dụng bắt đầu để xác minh mà cách ngăn xếp phát triển .. Hoặc làm một số kẹo mềm:

FooClass::FooClass() { 
    char dummy; 
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this); 
    if (displacement > 10000 || displacement < -10000) { 
     throw "Not on the stack - maybe.."; 
    } 
} 
+0

Cách tiếp cận thú vị! – hackworks

+0

Tôi nghĩ rằng điều này và giả sẽ luôn luôn gần gũi với nhau không có vấn đề nếu họ đang ở trong đống hoặc trong ngăn xếp – Vargas

+1

@Vargas - Tôi không đồng ý. 'giả' sẽ luôn nằm trên ngăn xếp, bởi vì nó là một biến cục bộ tự động. Con trỏ 'this' có thể trỏ tới stack (nếu FooClass được sử dụng như một biến cục bộ) hoặc heap (nếu FooClass được cấp phát trên heap, hoặc gộp lại trong một lớp mà sau đó được cấp phát trên heap). – pauldoo

3

@Nick

Điều này có thể bị phá vỡ bằng cách tạo lớp học có nguồn gốc từ hoặc tổng hợp Foo. Tôi nghĩ rằng những gì tôi đề nghị (trong khi không mạnh mẽ) sẽ vẫn làm việc cho các lớp học có nguồn gốc và tổng hợp.

ví dụ:

struct MyStruct { 
    Foo m_foo; 
}; 

MyStruct* p = new MyStruct(); 

Ở đây tôi đã tạo ra một thể hiện của 'Foo' trên đống, bỏ qua điều hành mới ẩn của Foo.

+0

+1 Bí quyết tuyệt vời! Loại đúc cũng có thể giúp – Viet

0

Bạn có thể khai báo nó làm giao diện và kiểm soát lớp triển khai trực tiếp hơn từ mã của riêng bạn.

0

Bởi vì tiêu đề gỡ lỗi có thể ghi đè lên chữ ký điều hành mới, cách tốt nhất là sử dụng ... chữ ký như một phương thuốc hoàn chỉnh:

private: 
void* operator new(size_t, ...) = delete; 
void* operator new[](size_t, ...) = delete; 
0

này có thể được ngăn ngừa bằng cách làm cho nhà xây dựng tư nhân và cung cấp một thành viên tĩnh để tạo một đối tượng trong ngăn xếp

Class Foo 
{ 
    private: 
     Foo(); 
     Foo(Foo&); 
    public: 
     static Foo GenerateInstance() { 
      Foo a ; return a; 
     } 
} 

điều này sẽ tạo đối tượng luôn trong ngăn xếp.

Các vấn đề liên quan