如何禁用在工厂方法之外创建/复制 obj?
How to disable creating/copying obj outside a Factory-Method?
我有一个类,它的有效载荷非常重,因此创建/复制/移动此类的实例非常昂贵。 由于它们在应用程序完成初始化后不会更改,因此无需创建此类的临时对象。我只需要将对象缓存在容器(std::map
),并在需要时提供"常量引用"。
必须强调的是,我正在寻找一种解决方案,可以避免在将对象添加到容器之前重复创建或不必要的复制对象(我不认为像提出的解决方案@getsoubl可以解决问题,因为它没有消除 doulbe 创建或不必要的复制)。
所以我想将构造函数方法安排到类体的"私有/受保护"部分,以禁止任何创建/复制/移动到"工厂方法"之外的行为。以下是我最初的解决方案:
class MyClass {
public:
// methods of the class
static const MyClass & findObject( int iKey ) {
auto pair = mapObjects.try_emplace( iKey, iKey );
if ( pair.second )
cout << "New object has been created" << endl;
return pair.first->second;
};
// deleted
MyClass() = delete;
MyClass( MyClass & ) = delete;
MyClass( MyClass && ) = delete;
MyClass( const MyClass & ) = delete;
MyClass( const MyClass && ) = delete;
MyClass & operator=( MyClass & ) = delete;
MyClass & operator=( MyClass && ) = delete;
MyClass & operator=( const MyClass & ) = delete;
MyClass & operator=( const MyClass && ) = delete;
private:
// vars of the class
static map<int, MyClass> mapObjects;
// vars of instance
string some_heavy_payload;
// methods of instance
MyClass( int iKey ) :
some_heavy_payload( std::to_string( iKey ) ) {};
};
map<int, MyClass> MyClass::mapObjects;
int main() {
const MyClass & obj = MyClass::findObject( 1 );
return EXIT_SUCCESS;
};
但是我陷入了一个矛盾,即"std::try-emplace"不能调用MyClass的构造函数。 编译器报告:"错误:'MyClass::MyClass(int)'在此上下文中是私有的"。
所以我尝试了解决方案2:
class MyClass {
public:
// methods of the class
static const MyClass & findObject( int iKey ) {
if ( mapObjects.find( iKey ) == mapObjects.cend() )
mapObjects[iKey] = MyClass( iKey );
return mapObjects[iKey];
};
// deleted
MyClass() = delete;
MyClass( MyClass & ) = delete;
MyClass( MyClass && ) = delete;
MyClass( const MyClass & ) = delete;
MyClass( const MyClass && ) = delete;
MyClass & operator=( MyClass & ) = delete;
MyClass & operator=( const MyClass & ) = delete;
MyClass & operator=( const MyClass && ) = delete;
private:
// vars of the class
static map<int, MyClass> mapObjects;
// vars of instance
string some_heavy_payload;
// methods of instance
MyClass( int iKey ) {
some_heavy_payload = std::to_string( iKey );
};
MyClass & operator=( MyClass && src ) {
some_heavy_payload = std::move( src.some_heavy_payload );
return *this;
};
};
map<int, MyClass> MyClass::mapObjects;
int main() {
const MyClass & obj = MyClass::findObject( 1 );
return EXIT_SUCCESS;
};
这次我得到一个错误:"使用已删除的函数'MyClass::MyClass()'"。 我想这是由 std::map 的"[]"运算符造成的,因为它试图调用 MyClass 的默认构造函数。
我怎样才能完成它?
如果你想锁定创建,只需将密钥传递给允许进入的每个人!
class MyClass {
class Key {
Key() = default;
friend class MyClass;
};
MyClass(MyClass const&) = delete;
MyClass& operator=(MyClass const&) = delete;
static map<int, MyClass> mapObjects;
public:
static MyClass const& findObject(int iKey) {
auto [iter, created] = mapObjects.try_emplace(iKey, Key(), iKey );
if (created)
std::cout << "New object has been createdn";
return iter->second;
};
MyClass(Key, int iKey)
: some_heavy_payload(std::to_string(iKey))
{}
private:
string some_heavy_payload;
};
您可以通过使用指针映射(复制或移动到映射中很便宜)而不是对象映射来实现此目的,如果您使用智能指针映射,那么您仍然可以让映射管理其中对象的生存期。
这里有一些概念验证代码,应该让你把这个想法推进。 在实践中,createA
和地图将隐藏在某个工厂函数中以填充地图。
请注意,A
构造函数是私有的,我们不能复制unique_ptr
,只能移动它。 此外,make_unique
是禁止的,因为A
有一个私有构造函数,但这没什么大不了的,在成本方面。 复制指针很便宜。
#include <iostream>
#include <map>
#include <memory>
class A
{
A () { std::cout << "Create A" << 'n'; }
A (const A &) = delete;
A &operator= (const A&) = delete;
A (A &&) = delete;
A &operator= (const A&&) = delete;
public:
~A () { std::cout << "Destroy A" << 'n'; }
friend void createA (int key);
};
static std::map <int, std::unique_ptr <A>> objects;
void createA (int key)
{
std::unique_ptr <A> a (new A);
objects.insert (std::pair <int, std::unique_ptr <A>> (key, std::move (a)));
}
int main ()
{
createA (1);
createA (2);
}
输出(通过地图显示对象生存期管理):
Create A
Create A
Destroy A
Destroy A
现场演示
或者,编写一个高效的移动构造函数(这通常并不困难)并将对象移动到映射中,而不是复制它们,如下所示:
#include <iostream>
#include <map>
#include <memory>
class A
{
A () { std::cout << "Create A" << 'n'; }
A (const A &) = delete;
A &operator= (const A&) = delete;
A &operator= (const A&&) = delete;
public:
A (const A &&) { std::cout << "Move A" << 'n'; }
~A () { std::cout << "Destroy A" << 'n'; }
friend void createA (int key);
};
static std::map <int, A> objects;
void createA (int key)
{
A a;
objects.insert (std::pair <int, A> (key, std::move (a)));
}
int main ()
{
createA (1);
createA (2);
}
输出:
Create A
Move A
Move A
Destroy A
Destroy A
Create A
Move A
Move A
Destroy A
Destroy A
Destroy A
Destroy A
现场演示
- 创建一个没有复制构造函数的类的 std::vector 的 std::vector
- 如何在新数组较小时创建新数组并将旧数组的最后一个元素复制到新数组中?
- 是否可以/希望创建不可复制的共享指针模拟(以启用weak_ptr跟踪/借用类型语义)?
- C++为具有引用成员变量的类创建复制构造函数
- 在c++中为链接列表创建复制构造函数/函数
- 我正在考虑为"A"类创建复制构造函数,但我不确定采用哪种方法
- 如何禁用在工厂方法之外创建/复制 obj?
- Windows Portable设备 - 创建 /复制 /删除新文件时通知
- 如何在具有指向对象的指针数组的类中创建复制构造函数和析构函数,其中对象本身具有指向整数的指针数组
- 为什么C++编译器会创建复制构造函数和复制赋值运算符
- 为什么在 c++ 中创建复制构造函数之前需要显式构造函数
- 试图在vector类中创建复制函数
- 为堆栈类创建复制构造函数
- 在模板中创建复制链表的函数时遇到问题
- 如何为链表创建复制构造函数
- 创建复制构造函数时调试断言失败
- 我不能为双向映射创建复制构造函数
- 为字符串类创建复制构造函数
- 如何在c++中使用std::list迭代器存储在std vector中,创建复制安全容器
- 从派生类创建复制构造函数和赋值运算符