Đối với những gì đáng giá ... bạn cũng có thể thu được từ việc sử dụng thành ngữ khác.
Tôi biết mẫu Flyweight
hoàn toàn là cơn thịnh nộ, nhưng ở đây bạn cũng có thể hưởng lợi từ việc không phân bổ hàng triệu đối tượng đó.
Nếu có vẻ lạ, hãy nghĩ đến đối tượng String
trong Python
. Như trong nhiều ngôn ngữ gần đây, String
là không thay đổi trong Python
. Tất nhiên, đối tượng bạn thao tác có thể thay đổi, nhưng thực tế String
không: tay cầm của bạn chỉ đơn giản là di chuyển.
Tất nhiên, Python
có bộ sưu tập rác tự động giúp việc này trở nên dễ dàng hơn nhiều, nhưng nó cũng có thể làm việc cho bạn. Dưới đây là một phác thảo:
class FooImpl;
class Foo
{
public:
explicit Foo(int i): mImpl(FooImpl::Build(i)) {}
int foo() const { return mImpl->foo(); }
void foo(int i) { mImpl = mImpl->foo(i); }
private:
const FooImpl* mImpl;
}; // class Foo
class FooImpl
{
public:
static const FooImpl* Build(int i)
{
typedef std::unordered_set<FooImpl> foos_type;
FooImpl tmp(i);
foos_type::iterator it = gFooImplCollection.insert(tmp);
return &(*it);
}
int foo() const { return mFoo; }
const FooImpl* foo(int i) const
{
return Build(i);
}
// Useful thingy
bool operator==(const FooImpl& rhs) const { return mFoo == rhs.mFoo; }
size_t hash() const { return mFoo; }
private:
explicit FooImpl(int i): mFoo(i) {}
int mFoo;
};
std::unordered_set<FooImpl> gFooImplCollection;
Tất nhiên, điều này rất thô, chỉ để cung cấp cho bạn một ý tưởng. Nếu số lượng các mục khác nhau có thể là quan trọng, bạn cần Bộ sưu tập rác.
Garbage Collection là một chủ đề khác, tôi thích để lại cho bạn với ý tưởng của một lớp Immutable
lõi (cho thấy chỉ const
phương pháp) và một tay cầm có thể thay đổi (mà chỉ đơn giản là thay đổi lớp lõi nó trỏ tới khi yêu cầu thay đổi).
Và bây giờ mà bạn đã dành thời gian để đọc, Boost có nó: Boost.Flyweight :)
Lưu ý:
Điều quan trọng là chính xác vẻ như, vì Foo
là vụ phải được phân bổ (trên ngăn xếp) hàng triệu lần, kích thước của nó sẽ càng gần với con trỏ càng tốt. Điều này được thực hiện bằng cách sử dụng Intrusive
couting tham chiếu (tôi hy vọng đó là những gì Boost làm). Ngoài ra, không cần thiết phải có các phương thức virtual
trong Foo
, virtual
nằm trong số FooImpl
và thực tế có thể gọi AbstractFactory
phía sau hậu trường.
Như vậy, kể từ Foo
:
- không có bất kỳ lớp cơ sở
- không có bất kỳ phương pháp ảo
- chỉ có một thuộc tính (một con trỏ)
kích thước hiệu quả của nó sẽ là kích thước của con trỏ ... đó là tốt nhất bạn có thể hy vọng nếu bạn không muốn lưu trữ một id một chi phí tra cứu incur tại mỗi cuộc gọi :)
Có chức năng ảo chỉ thêm 4 byte vào đối tượng (8 cho 64 bit). Bắt nguồn từ lớp cơ sở không có chi phí gì cả. (Những giả định đơn thừa kế.) – kennytm
Bạn cũng nên xem xét việc phân bổ nhanh hơn bằng cách sử dụng tùy chỉnh cấp phát. – yesraaj
Việc bạn nên làm phụ thuộc vào những gì bạn đang làm. Bạn đang làm gì đấy? – GManNickG