c++ - 尝试指向自动对象时应该使用什么策略?
问题描述
我正在开发一个相对较大的库(~13000 行)作为个人实用程序库。它专门使用 STL 容器和智能指针进行内存管理——但现在我发现自己处于一种情况,由于在 STL 中明显缺乏明显的解决方案,我可以看到使用普通指针。不过,我想保持现代 C++ 风格。
这是我的mcve:
Struct Foo
- 一个int
包装结构,显示调用了哪些成员函数。
struct Foo {
Foo(int x) {
this->x = x;
std::cout << "constructor\n";
}
Foo(const Foo& other) {
this->x = other.x;
std::cout << "copy constructor\n";
}
~Foo() {
std::cout << "destructor\n";
}
int x;
};
看着main
我创建了一个自动实例struct Foo
:
int main() {
Foo foo{ 0 };
std::cout << "\nfoo.x : " << foo.x << "\n\n";
}
输出 >
constructor
foo.x : 0
destructor
就这么简单。- 现在如果我想指向foo
和操作它的内容。
智能指针喜欢std::unique_ptr
或std::shared_ptr
不会达到这种效果(显然!)。使用std::make_unique<T>()
(/ std::make_shared<T>()
) 将动态分配内存并仅复制值:
Foo foo{ 0 };
std::unique_ptr<Foo> ptr = std::make_unique<Foo>(foo);
ptr->x = 2;
std::cout << "\nptr->x : " << ptr->x << '\n';
std::cout << "foo.x : " << foo.x << "\n\n";
输出 >
constructor
copy constructor
ptr->x : 2
foo.x : 0 // didn't change
destructor
destructor
所以这是行不通的。但是,它们的void reset(pointer _Ptr = pointer()) noexcept
成员函数允许直接分配一个指针:
std::unique_ptr<Foo> ptr;
Foo foo{ 0 };
ptr.reset(&foo);
ptr->x = 2;
std::cout << "\nptr->x : " << ptr->x << '\n';
std::cout << "foo.x : " << foo.x << "\n\n";
输出 >
constructor
ptr->x : 2
foo.x : 2
destructor
destructor //crash
但是崩溃!foo
get 正常解构,并且std::shared_ptr
还想解构它已经解构的解引用值。
HEAP [main.exe]:指定给 RtlValidateHeap(...) 的地址无效
使用 const 指针:
Foo foo{ 0 };
Foo* const ptr = &foo;
ptr->x = 2;
std::cout << "\nptr->x : " << ptr->x << '\n';
std::cout << "foo.x : " << foo.x << "\n\n";
输出 >
constructor
ptr->x : 2
foo.x : 2
deconstructor
- 1 次分配,1 次解除分配。
- 没有复制。
- 实际操纵价值。
到目前为止,指针感觉是最好的选择。
我只是在寻找一种指向自动分配对象的方法。到目前为止,如果不回到简单的指针,这似乎是非常困难的。
我自己提供了一种解决方案——使用/*const*/ std::reference_wrapper<T>
. (请随时纠正我有关此解决方案的信息)
但我不确定什么是最好的策略。指针?也许std::reference_wrapper
?我在使用std::shared_ptr
/时犯了错误std::unique_ptr
吗?
有没有更好、更直接的 STL 类?
解决方案
对冲我的赌注,因为你的目标还不清楚。
如果您想以明确所有权和生命周期的方式强烈地传递资源,那么智能指针是执行此操作的合适方法。标准库已经提供了它们,所以只需使用它们。
您已经发现这在很大程度上与自动存储持续时间的对象(您所谓的“在堆栈上”)不兼容。您可以使用自定义的无操作删除器来解决它,但老实说为什么?你只是让生活对自己来说太复杂了。当您以这种方式创建对象时,将为您选择所有权和生命周期,并且容易出错(悬空指针,伙计们!)。
只需为您拥有std::make_unique
或std::make_shared
动态分配您Foo
的 s,并以通常的方式使用生成的智能指针。
但是,显然我们看不到您的设计,也不太了解它。
如果您需要做的就是将对对象的引用传递给函数,它会做一件事然后返回,那么只需这样做!
void bar(const Foo& foo)
{
// do stuff
}
int main()
{
Foo foo;
bar(foo);
}
推荐阅读
- javascript - TS/ES6:实例化类而不调用构造函数
- apache-spark - 在 spark 2.3 中使用 G1GC 垃圾收集器
- ios - 如何创建一个只启动一个网站的 iPhone 应用程序
- c# - 如何简化在字符串中搜索关键字并按相关性排序的 LINQ 查询?
- solr - 对子文档进行排序
- php - Laravel + Vue:web.php / api.php 上的路由
- java - 如何防止错误:null > 0 java
- sql-server - 根据执行变量的结果更新现有表
- azure-functions - Azure Functions 运行时 2.0 - Cosmos DB 触发器 - 动态数据库和集合名称
- python - python3中的字节与str.encode