【发布时间】:2019-06-30 08:57:09
【问题描述】:
我正在开发一个相对较大的库(约 13000 行)作为个人实用程序库。它专门使用 STL 容器和智能指针进行内存管理——但现在我发现自己处于一种情况,由于在 STL 中明显缺乏明显的解决方案,我可以看到使用普通指针。不过,我想保持现代 C++ 风格。
这是我的mcve:
Struct Foo - 一个 int-wrapper 结构,显示调用了哪些成员函数。
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 also 想要解构其已经解构的解引用值。
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 类?
【问题讨论】:
-
为什么你想要指针语义?出于什么目的?你实际上并没有告诉我们你想要做什么。
-
您也可以使用自定义删除器吗?将一些对象分配在堆栈上而将其他对象分配在堆上也很危险!
-
为什么你认为这是糟糕的设计?
-
您尚未完全指定您的目标,但据我所知,它与那里接受的答案中描述的用例相匹配。人们在不需要时经常使用动态分配,但这并不意味着您应该不惜一切代价避免它。
-
它也不过是一个带有花哨名称的原始指针,真的
标签: c++ c++11 pointers memory-management reference