当试图指向自动对象时,应该使用什么策略
What strategy should be used when trying to point to automatic objects?
我正在开发一个相对较大的库(约13000行)作为个人实用程序库。它只使用STL容器和智能指针进行内存管理,但现在我发现自己的处境是,由于STL中明显缺乏明显的解决方案,我可以看到使用普通指针。不过,我想保持一种现代的C++风格。
这是我的简历:
结构Foo
-一个int
包装结构,显示调用了哪些成员函数。
struct Foo {
Foo(int x) {
this->x = x;
std::cout << "constructorn";
}
Foo(const Foo& other) {
this->x = other.x;
std::cout << "copy constructorn";
}
~Foo() {
std::cout << "destructorn";
}
int x;
};
查看main
,我创建了一个struct Foo
:的自动实例
int main() {
Foo foo{ 0 };
std::cout << "nfoo.x : " << foo.x << "nn";
}
输出>
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 << "nn";
输出>
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 << "nn";
输出>
constructor
ptr->x : 2
foo.x : 2
destructor
destructor //crash
但是崩溃!foo
通常被解构,而std::shared_ptr
也想要解构其已经被解构的去引用值。
HEAP〔main.exe〕:为RtlValidateHeap(…)指定的地址无效
使用常量指针:
Foo foo{ 0 };
Foo* const ptr = &foo;
ptr->x = 2;
std::cout << "nptr->x : " << ptr->x << 'n';
std::cout << "foo.x : " << foo.x << "nn";
输出>
constructor
ptr->x : 2
foo.x : 2
deconstructor
- 1个分配,1个解除分配
- 禁止复制
- 实际操作值
到目前为止,指针感觉是最好的选择。
我只是在寻找一种指向自动分配对象的方法。到目前为止,如果不回到简单的指针,这似乎令人惊讶地困难。
我自己提供了一个解决方案,那就是使用/*const*/ std::reference_wrapper<T>
。(请随时纠正我的这个解决方案)
但我不确定什么是最好的策略。指针?可能是CCD_ 14?我在使用std::shared_ptr
/std::unique_ptr
时犯了错误吗?
是否有更好、更直接的STL类
我在这一点上有点对冲,因为你的目标不明确。
如果您想以明确所有权和生存期的方式强力传递资源,那么智能指针是实现这一点的合适方法。标准库已经提供了它们,所以只需使用它们。
您已经发现,这在很大程度上与自动存储持续时间的对象(您称之为"在堆栈上")不兼容。你可以使用自定义的无操作删除程序来解决这个问题,但老实说为什么?你只是让生活变得太复杂了。当你以这种方式创建对象时,所有权和生存期都是为你选择的,而且很容易出错(伙计们,悬挂指针!)。
只需让std::make_unique
或std::make_shared
为您动态分配Foo
,并以通常的方式使用生成的智能指针。
然而,显然我们看不到你的设计,也不太了解它。
如果您所需要做的只是将对对象的引用传递给函数,这将执行一件事然后返回,那么只需执行即可!
void bar(const Foo& foo)
{
// do stuff
}
int main()
{
Foo foo;
bar(foo);
}
但我不确定什么是最好的策略。指针?
可能。若您需要指向一个对象,那个么指针是一个不错的选择。
参考可能是另一个:
Foo foo{ 0 };
Foo& ref = foo;
ref = 2;
如果引用是足够的,那么它通常比指针更可取。
我使用
std::shared_ptr
/std::unique_ptr
时出错了吗?
是。您获得了一个自动变量的所有权。这是不允许的。
在第一个示例中,您制作了一个对象的副本,期望对副本的修改会影响原始对象。
std::reference_wrapper
:
Foo foo{ 0 };
std::reference_wrapper<Foo> ref = foo;
ref.get().x = 2;
std::cout << "nref.x : " << ref.get().x << 'n';
std::cout << "foo.x : " << foo.x << "nn";
输出>
constructor
ref.x : 2
foo.x : 2
deconstructor
它的行为就像一个指针。好吧,从它的实现来看,是一个指针:
template<class _Ty>
class reference_wrapper
: public _Weak_types<_Ty>::type
{
public:
/*...*/
private:
_Ty * _Ptr; //<---
};
对于pointer const
效果(Foo* const
),它可以声明为const std::reference_wrapper<Foo>
,不允许更改其指针地址。
Foo foo{ 0 };
const std::reference_wrapper<Foo> ref = foo;
Foo foo2{ 2 };
ref = foo2; //error
错误C2678二进制"=":找不到接受类型为"const std::reference_wrapper"的左侧操作数的运算符(或者没有可接受的转换)
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 警告处理为错误这里有什么问题
- 什么时候调用组成单元对象的析构函数
- #定义c-预处理器常量..我做错了什么
- 为同一类提供不同比较运算符的最佳策略是什么?
- 在C++中使用异常的可能的错误处理策略是什么,它们的后果和影响是什么
- 当试图指向自动对象时,应该使用什么策略
- 在 boost::intrusive::unordered_set 的存储桶中使用了什么存储策略
- 静态多态性策略和CRTP有什么区别
- 摆脱"warning C4267 possible loss of data"的最佳策略是什么?
- 暴力迫使程序以不同的输入崩溃的策略是什么?
- 在 c++ 中存储对象的最佳策略是什么,确保名称唯一并能够在以后有效地检索它们
- 通过组策略安装 VC++ 可再发行组件的最佳方法是什么?
- 您在软件中编写日志以处理可能大量的日志消息的策略是什么
- 在c/c++中,在源文件之间共享变量的最佳策略是什么
- 什么时候应该使用std::async和sync作为策略
- 异步方案使用什么shared_ptr策略
- 在交易客户中,什么是正确的策略实施方式?
- 不同的编译器用来处理数字转换中的溢出的常见策略是什么?
- 特质和策略有什么区别