【问题标题】:Compare the habits between move and smart pointer in C++?比较 C++ 中移动和智能指针的习惯?
【发布时间】:2017-10-31 16:40:40
【问题描述】:

在 C++11/14 中,可以通过move 或 smark 指针来传输对象。

(1)这是move的示例:

class MoveClass {
private:
    int *tab_;
    int alloc_;
    void Reset() {
        tab_ = nullptr;
        alloc_ = 0;
    }
    void Release() {
        if (tab_) delete[] tab_;
        tab_ = nullptr;
        alloc_ = 0;
    }

public:
    MoveClass() : tab_(nullptr), alloc_(0) {}
    ~MoveClass() {
        Release();
    }
    MoveClass(MoveClass && other) : tab_( other.tab_ ), alloc_( other.alloc_ ) {
        other.Reset();
    }
    MoveClass & operator=(MoveClass && other) {
        if (this == &other) return *this;
        std::swap(tab_, other.tab_);
        std::swap(alloc_, other.alloc_);
        return *this;
    }
    void DoSomething() { /*...*/ }
};

当我们使用这个可移动的MoveClass时,我们可以这样写代码:

int main() {
    MoveClass a;
    a.DoSomething();  // now a has some memory resource
    MoveClass b = std::move(a);  // move a to b
    return 0;
}

总是写move-constructor/move-operator=很无聊,用shared_ptr/unique_ptr有时候效果一样,就像java一样,到处都是引用/指针。

(2)示例如下:

class NoMoveClass {
private:
    int *tab_;
    int alloc_;
    void Release() {
        if (tab_) delete[] tab_;
        tab_ = nullptr;
        alloc_ = 0;
    }

public:
    NoMoveClass() : tab_(nullptr), alloc_(0) {}
    ~NoMoveClass() {
        Release();
    }
    MoveClass(MoveClass && other) = delete;
    MoveClass & operator=(MoveClass && other) = delete;
    void DoSomething() { /*...*/ }
};

我们可以这样使用它:

int main() {
    std::shared_ptr<NoMoveClass> a(new NoMoveClass());
    a->DoSomething();
    std::shared_ptr<NoMoveClass> b = a; // also move a to b by copy pointer.
    return 0;
}

总是使用第二个是个好习惯吗?

为什么很多库,STL 使用第一个,而不是第一个?

【问题讨论】:

  • 在您的第一个示例中,MoveClass 位于堆栈上,第二个示例位于堆上。在堆上分配所有内容并使用智能指针会带来很大的开销。更不用说语义不同了。
  • @KinanAlSarmini 堆上的 'tab_' 和 'alloc_' 会花费这么多吗?有没有性能基准数据?
  • @zhaochenyou 一个额外的间接性肯定会花费一些东西,但关键是语义不同,这两种技术不可互换
  • @Ap31 是的,有时候,我只是想少写一些代码
  • C++ 让您可以随心所欲。如果您发现这适合您的需求,并且性能成本对于 您的 应用程序来说微不足道,那就去吧。

标签: c++ c++11 shared-ptr move


【解决方案1】:

总是写 move-constructor/move-operator= 很无聊

几乎从不需要编写自己的移动构造函数/赋值,因为(正如您所提到的)C++ 为您提供了许多基本资源管理器 - 智能指针、容器、智能锁等。

通过依赖类中的那些,您可以启用默认的移动操作,从而最大限度地减少代码大小和正确的语义:

class MoveClass {
private:
    std::vector<int> data;
public:
    void DoSomething() { /*...*/ }
};

现在您可以像在 (1) 中一样使用您的类,也可以作为其他类中的成员使用,您可以确定它具有移动语义,并且您可以用尽可能少的代码量来实现。

关键是通常只需要为 STL 可能已经涵盖的最低级别的类实现移动操作,或者如果需要一些奇怪的特定行为 - 这两种情况应该非常罕见并且不会导致“总是编写 move-constructor/move-operator=".

还请注意,虽然方法 (1) 不必要地冗长,但 (2) 是不可接受的 - 你有一个资源管理类没有完成它的工作并且因此,您必须在代码中的任何位置将其包装在智能指针中,使其更难理解,最终导致代码比 (1)

还要多

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2012-07-01
    • 1970-01-01
    • 2010-09-28
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    相关资源
    最近更新 更多