You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在派生类中保留shared_ptr并传递右值给基类构造函数?

问题描述

我有一个小型类继承体系,需要将std::shared_ptr传递给接受右值的基类构造函数,同时希望在派生类中保留该std::shared_ptr。简化后的问题代码如下:

class Base {
  public:
    Base(std::shared_ptr<int>&& p)
        : a_{p}
    {
    }

  private:
    std::shared_ptr<int> a_;
};

class Derived : public Base {
  public:
    Derived(std::shared_ptr<int> p)
        : Base(copy_shared_ptr(p)) // 此写法不合法,希望实现类似逻辑
    {
    }

  private:
    std::shared_ptr<int> copy_shared_ptr(std::shared_ptr<int> p)
    {
        p_ = p; // 会触发段错误,因为p_尚未初始化
        std::cout << "Now p_ is " << p_.use_count() << std::endl;
        return p_;
    }

    std::shared_ptr<int> p_;
};

int main() { Derived d{std::make_shared<int>(5)}; }

问题核心在于:基类构造函数会优先于派生类成员变量执行,因此无法在传递shared_ptr给基类前先初始化派生类的p_,直接赋值未初始化的p_会触发未定义行为(段错误)。

解决方案

方法一:复制+移动,兼顾效率与需求

利用std::shared_ptr的拷贝特性,先复制一份给基类作为右值传递,再将原构造函数参数移动给派生类成员,避免不必要的拷贝开销:

#include <memory>
#include <iostream>

class Base {
  public:
    Base(std::shared_ptr<int>&& p)
        : a_{std::move(p)} // 用std::move转移临时右值所有权,避免基类构造时的拷贝
    {
    }

  private:
    std::shared_ptr<int> a_;
};

class Derived : public Base {
  public:
    // 参数使用值传递,方便后续移动操作
    Derived(std::shared_ptr<int> p)
        : Base(std::shared_ptr<int>(p)), // 复制p生成临时右值,传递给基类
          p_(std::move(p)) // 将原参数的所有权移动给p_,无额外拷贝
    {
        std::cout << "Derived p_ use count: " << p_.use_count() << std::endl;
    }

  private:
    std::shared_ptr<int> p_;
};

int main() { 
    Derived d{std::make_shared<int>(5)}; 
}

方法二:委托构造优先初始化派生类成员

如果想优化拷贝次数,可以通过私有委托构造函数先初始化派生类成员,再基于成员复制出右值传递给基类:

#include <memory>
#include <iostream>

class Base {
  public:
    Base(std::shared_ptr<int>&& p)
        : a_{std::move(p)}
    {
    }

  private:
    std::shared_ptr<int> a_;
};

class Derived : public Base {
  private:
    // 私有委托构造:先初始化p_,再给基类传值
    Derived(std::shared_ptr<int> p, int)
        : p_(std::move(p)),
          Base(std::shared_ptr<int>(p_)) // 复制p_生成右值传给基类
    {
        std::cout << "Derived p_ use count: " << p_.use_count() << std::endl;
    }

  public:
    Derived(std::shared_ptr<int> p)
        : Derived(std::move(p), 0) // 委托给私有构造函数
    {
    }

  private:
    std::shared_ptr<int> p_;
};

int main() { 
    Derived d{std::make_shared<int>(5)}; 
}

关键说明

  • 原代码的错误根源是在派生类成员初始化前对其赋值,这属于未定义行为,必须避免。
  • 值传递的构造函数参数是传入对象的副本,我们可以安全地将其移动给派生类成员,同时复制一份给基类使用。
  • 基类构造中使用std::move(p)能直接转移临时右值的所有权,减少引用计数的操作开销。

内容的提问来源于stack exchange,提问作者SupAl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:13:21