将 emplace_back 对象转换为 std::list 的正确方法
Proper way to emplace_back object into std::list
我有一个 class,其中包含各种成员(主要是整数、浮点数和一些动态容器)。我有一个 std::list 我的 class 对象。在此 class 的构造函数中,在设置所有参数后调用
myclassobjects.emplace_back(*this)
这行得通并且似乎不会导致任何分配问题;我从来没有 sigsegv 问题或类似问题。然而,我并不完全相信这是正确的做法,或者它不会导致缓慢的内存泄漏。
这种方法使用安全吗,会不会导致内存泄漏?如果是,'proper' 构建对象并立即将其放入 std::list 中的方法是什么?
确实不可能将您的对象存储在 std::list
或任何其他容器中。根据对象的标准定义,对象是 存储区域 。一个存储区域不能存储,它只是是。
假设 X 是一个现有对象。容器不能存储 X 本身,而是以某种方式与 X 相关的值。有两种选择。
- 存储 X 的 副本。
- 将(智能)指针或引用包装器存储到 X。
由于您正在部署 *this
,因此您正在存储一个副本。这可能是也可能不是您需要的。
要存储裸指针,您必须emplace_back(this)
,当然还要更改列表的类型。这是危险的,因为当 X 不复存在时,您的列表可能仍然有一个指向它的悬空指针。你需要确保它不会发生。
您可能要考虑存储共享指针,但如果您想通过继承 enable_shared_from_this
来启用它,请注意 。
首先emplace_back
通过转发参数就地构造一个对象。所以你最终做的是用参数 *this
.
调用你的 class 的复制构造函数
我正在尝试考虑需要将对象添加到构造函数内的列表的情况,但我遇到了困难。我认为有更好的选择。
从构造函数外部将其放置在列表中
简单创建如下。
myclassobjects.emplace_back(/*constructor params*/);
在 C++17 中,这甚至 return 是对新创建对象的引用
MyClass& myclass_ref = myclassobjects.emplace_back(/*constructor params*/);
do_something_with_my_class_object(myclass_ref);
这是最干净、最有效的方法。它还有一个额外的好处,即您可以创建本地对象,而无需在需要时将它们添加到列表中。
使用工厂方法将其添加到列表中
如果您绝对必须拥有列表中的每个对象并且您不希望它是一个副本,请使用静态工厂方法。如果列表和被调用者必须共享所有权,您可以使用 std::shared_ptr
的列表并执行以下操作。
MyClass {
private:
MyClass(); // private constructor forbids on the stack variables
public:
static std::shared_ptr<MyClass> create_instance() {
auto ptr = make_shared<MyClass>(); // We can access the constructor here
myclass_objects.emplace_back(ptr);
return ptr;
}
}
另一方面,如果你的列表保证比对象上的被调用者的处理程序长寿,那么拥有一个包含对象和 return 引用的 std::unique_ptr
列表更合适给他们。
MyClass {
private:
MyClass(); // private constructor forbids on the stack variables
public:
// pre C++17
static MyClass& create_instance() {
auto ptr = make_unique<MyClass>();
auto& ref = *ptr; // Store ref before we move pointer
myclass_objects.emplace_back(std::move(ptr));
return ref;
}
// C++17
static MyClass& create_instance() {
auto ptr = make_unique<MyClass>();
return *(myclass_objects.emplace_back(std::move(ptr)));
}
}
当然,这些示例仅涵盖默认构造函数。因为您通常需要使用更多的构造函数,所以您可能需要一个模板化的 create_instance
将其参数转发给构造函数。
我有一个 class,其中包含各种成员(主要是整数、浮点数和一些动态容器)。我有一个 std::list 我的 class 对象。在此 class 的构造函数中,在设置所有参数后调用
myclassobjects.emplace_back(*this)
这行得通并且似乎不会导致任何分配问题;我从来没有 sigsegv 问题或类似问题。然而,我并不完全相信这是正确的做法,或者它不会导致缓慢的内存泄漏。
这种方法使用安全吗,会不会导致内存泄漏?如果是,'proper' 构建对象并立即将其放入 std::list 中的方法是什么?
确实不可能将您的对象存储在 std::list
或任何其他容器中。根据对象的标准定义,对象是 存储区域 。一个存储区域不能存储,它只是是。
假设 X 是一个现有对象。容器不能存储 X 本身,而是以某种方式与 X 相关的值。有两种选择。
- 存储 X 的 副本。
- 将(智能)指针或引用包装器存储到 X。
由于您正在部署 *this
,因此您正在存储一个副本。这可能是也可能不是您需要的。
要存储裸指针,您必须emplace_back(this)
,当然还要更改列表的类型。这是危险的,因为当 X 不复存在时,您的列表可能仍然有一个指向它的悬空指针。你需要确保它不会发生。
您可能要考虑存储共享指针,但如果您想通过继承 enable_shared_from_this
来启用它,请注意
首先emplace_back
通过转发参数就地构造一个对象。所以你最终做的是用参数 *this
.
我正在尝试考虑需要将对象添加到构造函数内的列表的情况,但我遇到了困难。我认为有更好的选择。
从构造函数外部将其放置在列表中
简单创建如下。
myclassobjects.emplace_back(/*constructor params*/);
在 C++17 中,这甚至 return 是对新创建对象的引用
MyClass& myclass_ref = myclassobjects.emplace_back(/*constructor params*/);
do_something_with_my_class_object(myclass_ref);
这是最干净、最有效的方法。它还有一个额外的好处,即您可以创建本地对象,而无需在需要时将它们添加到列表中。
使用工厂方法将其添加到列表中
如果您绝对必须拥有列表中的每个对象并且您不希望它是一个副本,请使用静态工厂方法。如果列表和被调用者必须共享所有权,您可以使用 std::shared_ptr
的列表并执行以下操作。
MyClass {
private:
MyClass(); // private constructor forbids on the stack variables
public:
static std::shared_ptr<MyClass> create_instance() {
auto ptr = make_shared<MyClass>(); // We can access the constructor here
myclass_objects.emplace_back(ptr);
return ptr;
}
}
另一方面,如果你的列表保证比对象上的被调用者的处理程序长寿,那么拥有一个包含对象和 return 引用的 std::unique_ptr
列表更合适给他们。
MyClass {
private:
MyClass(); // private constructor forbids on the stack variables
public:
// pre C++17
static MyClass& create_instance() {
auto ptr = make_unique<MyClass>();
auto& ref = *ptr; // Store ref before we move pointer
myclass_objects.emplace_back(std::move(ptr));
return ref;
}
// C++17
static MyClass& create_instance() {
auto ptr = make_unique<MyClass>();
return *(myclass_objects.emplace_back(std::move(ptr)));
}
}
当然,这些示例仅涵盖默认构造函数。因为您通常需要使用更多的构造函数,所以您可能需要一个模板化的 create_instance
将其参数转发给构造函数。