移动智能指针两次与复制

Posted

技术标签:

【中文标题】移动智能指针两次与复制【英文标题】:moving smart pointers twice vs copying 【发布时间】:2019-11-29 11:18:23 【问题描述】:

在性能、内存等方面是否存在显着差异:

#1:将一个指针移动到一个临时指针,再往回移动,然后删除临时指针 #2:将指针复制到临时指针,然后删除临时指针

我有以下代码,对象的两个指针BaseDerived (派生自 Base) 允许存储在 Base 对象的指针向量中,读取向量时,我需要检查是否需要 dynamic_pointer_cast 指针,以免数据被切掉。

#include "Base.h"
#include "Derived.h"

class Base

public:
    Base() ;
    ~Base() ;
;

class Derived: public Base

public:
    Derived() ;
    ~Derived() ;
;

int main()

    std::vector<std::shared_ptr<Base>> vectorOfBaseObjects;

    std::shared_ptr<Base> base = std::make_shared<Base>();
    std::shared_ptr<Derived> derived = std::make_shared<Derived>();

    vectorOfBaseObjects.push_back(base);
    vectorOfBaseObjects.push_back(derived);

    for (auto &it : vectorOfBaseObjects) 
        // #1: Move pointer to a temporary location and move it back when done
        if (std::shared_ptr<Derived> tmp_ptr = std::move(std::dynamic_pointer_cast<Derived>(it))) 
            // Do something with the derived object
            it = std::move(tmp_ptr);
        

        // #2: Create a new temporary pointer
        if (std::shared_ptr<Derived> tmp_ptr = std::dynamic_pointer_cast<Derived>(it)) 
            // Do something with the derived object
        
    

这两种说法都很好,我唯一能解决的问题可能是

#1:在极少数情况下,多线程应用程序中缺少指针位置,这可能会成为问题。 #2:在内存中分配的额外位置,这根本不应该成为问题。

【问题讨论】:

dynamic_pointer_cast 按值返回,所以没有区别。 另请注意“我需要检查是否需要动态指针转换指针,以免数据被切掉。”是完全错误的。 Derived 对象不是被复制或移动的对象,不可能切片。 @Caleth "请注意it = std::move(tmp_ptr); 毫无意义。"一开始我也是这么想的,但如果我不这样做,我将无法在完成循环后再访问向量中的指针。 - “没有切片的可能。”啊,好的,很高兴知道! 第一个版本似乎违背了我拥有shared_ptr 的部分目的。您重新引入了shared_ptr 应该防止的潜在错误。 @user253751,这是不正确的,因为 std::dynamic_pointer_cast() 返回一个 new 共享指针,并且不会更改 itstd::move() 在那里什么也没做,因为它作用于一个右值。 【参考方案1】:

这两种情况几乎是等价的,因为std::dynamic_pointer_cast() 返回一个新的共享指针。 it 没有从这个表达式中移出:

std::move(std::dynamic_pointer_cast<Derived>(it))

强制转换的结果已经是一个 xvalue,所以这与

std::dynamic_pointer_cast<Derived>(it)

唯一的区别是将指针复制回it。如果您没有更改它所指向的内容,那么这是一个浪费的声明。

【讨论】:

【参考方案2】:

如果您担心创建新shared_ptrs 的速度,那么tmp_ptr 可能甚至不需要成为shared_ptr。使用原始指针看起来像这样:

Derived* tmp_ptr = dynamic_cast<Derived*>(it.get());

【讨论】:

以上是关于移动智能指针两次与复制的主要内容,如果未能解决你的问题,请参考以下文章

018-智能指针

在结构或类中使用智能指针

C11新特性之智能指针

为啥mac不需要包含智能指针? [复制]

智能指针原理及实现- unique_ptr

在具有智能指针的类上正确实现复制构造函数和等于运算符