如何在工厂方法之外禁用 creating/copying obj?
How to disable creating/copying obj outside a Factory-Method?
我有一个 class,它的负载非常重,因此 create/copy/move 这个 class 的一个实例非常昂贵。
由于它们在应用程序完成初始化后不会更改,因此无需创建此 class 的临时对象。我只需要在容器中缓存对象(std::map
),并在需要时提供"const reference"。
必须强调的是,我正在寻找一种解决方案,可以避免在将对象添加到容器之前进行双重创建或不必要的复制(我不认为@getsoubl 提出的解决方案可以解决问题,因为它不会消除双倍创建或不必要的复制)。
所以我想将构造方法安排到class主体的"private/protected"部分,以禁止"Factory-Method"之外的任何creating/copying/moving。以下是我的原始解决方案:
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 的构造函数。
编译器报告:"error: ‘MyClass::MyClass(int)’ is private within this context".
所以我尝试了解决方案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;
};
这次我得到一个错误:"use of deleted function ‘MyClass::MyClass()’"。
我猜这是由 std::map 的“[]”运算符导致的,因为它试图调用 MyClass.
的默认构造函数
我怎样才能完成它?
您可以通过使用指针映射(复制或移动到映射中的成本很低)而不是对象映射来实现这一点,如果您使用智能指针映射,那么您仍然可以拥有map 管理其中对象的生命周期。
这里有一些 proof-of-concept 代码,可以让您推进这个想法。实际上,createA
和地图将隐藏在一些工厂函数中以填充地图。
请注意 A
的构造函数是私有的,我们不能复制 unique_ptr
,只能移动它。此外,make_unique
是 off-limits 因为 A
有一个私有构造函数,但这没什么大不了的,cost-wise。复制指针很便宜。
#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
如果您想锁定创建,只需将密钥传递给允许进入的每个人!
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 created\n";
return iter->second;
};
MyClass(Key, int iKey)
: some_heavy_payload(std::to_string(iKey))
{}
private:
string some_heavy_payload;
};
我有一个 class,它的负载非常重,因此 create/copy/move 这个 class 的一个实例非常昂贵。
由于它们在应用程序完成初始化后不会更改,因此无需创建此 class 的临时对象。我只需要在容器中缓存对象(std::map
),并在需要时提供"const reference"。
必须强调的是,我正在寻找一种解决方案,可以避免在将对象添加到容器之前进行双重创建或不必要的复制(我不认为@getsoubl 提出的解决方案可以解决问题,因为它不会消除双倍创建或不必要的复制)。
所以我想将构造方法安排到class主体的"private/protected"部分,以禁止"Factory-Method"之外的任何creating/copying/moving。以下是我的原始解决方案:
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 的构造函数。 编译器报告:"error: ‘MyClass::MyClass(int)’ is private within this context".
所以我尝试了解决方案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;
};
这次我得到一个错误:"use of deleted function ‘MyClass::MyClass()’"。 我猜这是由 std::map 的“[]”运算符导致的,因为它试图调用 MyClass.
的默认构造函数我怎样才能完成它?
您可以通过使用指针映射(复制或移动到映射中的成本很低)而不是对象映射来实现这一点,如果您使用智能指针映射,那么您仍然可以拥有map 管理其中对象的生命周期。
这里有一些 proof-of-concept 代码,可以让您推进这个想法。实际上,createA
和地图将隐藏在一些工厂函数中以填充地图。
请注意 A
的构造函数是私有的,我们不能复制 unique_ptr
,只能移动它。此外,make_unique
是 off-limits 因为 A
有一个私有构造函数,但这没什么大不了的,cost-wise。复制指针很便宜。
#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
如果您想锁定创建,只需将密钥传递给允许进入的每个人!
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 created\n";
return iter->second;
};
MyClass(Key, int iKey)
: some_heavy_payload(std::to_string(iKey))
{}
private:
string some_heavy_payload;
};