C++ boost库----share_from_this类的作用和实现原理

本文探讨了在Boost库中使用enable_shared_from_this的具体场景与原理。解释了为何在需要传递自身实例时使用shared_ptr而非this指针,并详细分析了通过share_from_this()方法返回自身shared_ptr的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用boost库时,经常会看到如下的类

class A:public enable_share_from_this<A>

在什么情况下要使类A继承enable_share_from_this?

使用场合:当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。

我们就使类A继承enable_share_from_this,然后通过其成员函数share_from_this()返回当指向自身的share_ptr。

以上有2个疑惑:

1.把当前类对象作为参数传给其他函数时,为什么要传递share_ptr呢?直接传递this指针不可以吗?

一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者delete了该对象,而share_tr此时还指向该对象。

2.这样传递share_ptr可以吗?share_ptr<this>

这样会造成2个非共享的share_ptr指向一个对象,最后造成2次析构该对象。

boost官方文档中一个非常典型的例子:http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/tutorial/tutdaytime3/src.html

部分代码:

复制代码
 1 class tcp_connection
 2   : public boost::enable_shared_from_this<tcp_connection>
 3 {
 4 public:
 5   typedef boost::shared_ptr<tcp_connection> pointer;
 6 
 7   static pointer create(boost::asio::io_service& io_service)
 8   {
 9     return pointer(new tcp_connection(io_service));
10   }
11 
12   tcp::socket& socket()
13   {
14     return socket_;
15   }
16 
17   void start()
18   {
19     message_ = make_daytime_string();
20 
21     boost::asio::async_write(socket_, boost::asio::buffer(message_),
22         boost::bind(&tcp_connection::handle_write, shared_from_this(),
23           boost::asio::placeholders::error,
24           boost::asio::placeholders::bytes_transferred));
25   }
26 
27 private:
28   tcp_connection(boost::asio::io_service& io_service)
29     : socket_(io_service)
30   {
31   }
32 
33   void handle_write(const boost::system::error_code& /*error*/,
34       size_t /*bytes_transferred*/)
35   {
36   }
37 
38   tcp::socket socket_;
39   std::string message_;
40 };
复制代码

类tcp_connection继承enable_share_from_this,在22行里,它的成员函数start(),通过share_from_this返回指向自身的share_ptr。

实现原理:

share_from_this()是如何返回指向该对象的share_ptr的?显然它不能直接return share_ptr<this>。因为它返回的share_ptr必须和管理该对象的share_ptr是共享的,也就是说返回的share_ptr的引用计数和管理该对象的share_ptr的引用计数是相同的。其实enable_share_from_this就存储了管理该对象的share_ptr的引用计数,通过weak_ptr来实现。在enable_share_from_this,里有一个成员weak_this_。

但现在的问题是:何时初始化这个 weak_ptr ?因为类对象生成时还没有生成相应的用来管理这个对象的 shared_ptr 。其实是通过share_ptr的构造函数中初始化这个weak_ptr的.

shared_ptr 定义了如下构造函数:
1  template<class Y>
2 explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete
3 {
4   boost::detail::sp_pointer_construct( this, p, pn );
5 }
里面调用了  boost::detail::sp_pointer_construct 
复制代码
1 template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr< T > * ppx, Y * p, boost::detail::shared_count & pn )
2 {
3    boost::detail::shared_count( p ).swap( pn );
4    boost::detail::sp_enable_shared_from_this( ppx, p, p );
5 }
复制代码
 里面又调用了boost::detail::sp_enable_shared_from_this
 
share_ptr有2个该重载函数
复制代码
1 template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe )
2 {
3   if( pe != 0 )
4  {
5    pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
6  }
7 }
复制代码
1 inline void sp_enable_shared_from_this( ... )
2 {
3 }

由于我们的类是继承enable_share_from_this,所以调用的是前者

里面又调用了 enable_shared_from_this 的 _internal_accept_owner :
复制代码
template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const
{
  if( weak_this_.expired() )
  {
    weak_this_ = shared_ptr<T>( *ppx, py );
  }
}
复制代码

最后,在这里对enable_shared_from_this 的成员 weak_this_ 进行拷贝赋值,使得整个 weak_ptr 作为类对象shared_ptr 的一个观察者。当调用share_from_this()时,就可以从这个 weak_ptr 来生成了,且引用计数是相同的。

复制代码
1 shared_ptr<T const> shared_from_this() const
2 {
3  shared_ptr<T const> p( weak_this_ );
4  BOOST_ASSERT( p.get() == this );
5  return p;
6 }
复制代码

 

 

(foundationpose) root@localhost:/mnt/e/wsl/foundationpose-main# CMAKE_PREFIX_PATH=$CONDA_PREFIX/root\anaconda3\envs\foundationpose\lib\python3.9\site-packages/pybind11/share/cmake/pybind11 bash build_all_conda.sh -- The C compiler identification is GNU 13.3.0 -- The CXX compiler identification is GNU 13.3.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Found Python3: /root/anaconda3/envs/foundationpose/bin/python3 (found version "3.9.23") found components: Interpreter Development -- Found Boost: /root/anaconda3/envs/foundationpose/lib/cmake/Boost-1.82.0/BoostConfig.cmake (found version "1.82.0") found components: python -- Found Boost: /root/anaconda3/envs/foundationpose/lib/cmake/Boost-1.82.0/BoostConfig.cmake (found version "1.82.0") found components: system program_options -- Found OpenMP_C: -fopenmp (found version "4.5") -- Found OpenMP_CXX: -fopenmp (found version "4.5") -- Found OpenMP: TRUE (found version "4.5") -- Performing Test HAS_FLTO -- Performing Test HAS_FLTO - Success -- Found pybind11: /root/anaconda3/envs/foundationpose/include (found version "2.13.6") -- Configuring done -- Generating done -- Build files have been written to: /mnt/e/wsl/foundationpose-main/mycpp/build make[1]: Entering directory '/mnt/e/wsl/foundationpose-main/mycpp/build' make[2]: Entering directory '/mnt/e/wsl/foundationpose-main/mycpp/build' Scanning dependencies of target mycpp make[2]: Leaving directory '/mnt/e/wsl/foundationpose-main/mycpp/build' make[2]: Entering directory '/mnt/e/wsl/foundationpose-main/mycpp/build' [ 33%] Building CXX object CMakeFiles/mycpp.dir/src/app/pybind_api.cpp.o [ 66%] Building CXX object CMakeFiles/mycpp.dir/src/Utils.cpp.o /mnt/e/wsl/foundationpose-main/mycpp/src/app/pybind_api.cpp: In function ‘vectorMatrix4f cluster_poses(float, float, const vectorMatrix4f&, const vectorMatrix4f&)’: /mnt/e/wsl/foundationpose-main/mycpp/src/app/pybind_api.cpp:26:38: warning: format ‘%d’ expects argument of type ‘in ’, but argument 2 has type ‘std::vector<Eigen::Matrix<float, 4, 4>, Eigen::aligned_allocator<Eigen::Matrix<float, 4, 4> > >::size_type’ {aka ‘long unsigned int’} [-Wformat=] 26 | printf("num original candidates = %d\n",poses_in.size()); | ~^ ~~~~~~~~~~~~~~~ | | | | int std::vector<Eigen::Matrix<float, 4, 4>, Eigen::aligned_allocator<Eigen::Matrix<float, 4, 4> > >::size_type {aka long unsigned int} | %ld /mnt/e/wsl/foundationpose-main/mycpp/src/app/pybind_api.cpp:66:42: warning: format ‘%d’ expects argument of type ‘in ’, but argument 2 has type ‘std::vector<Eigen::Matrix<float, 4, 4>, Eigen::aligned_allocator<Eigen::Matrix<float, 4, 4> > >::size_type’ {aka ‘long unsigned int’} [-Wformat=] 66 | printf("num of pose after clustering: %d\n",poses_out.size()); | ~^ ~~~~~~~~~~~~~~~~ | | | | int std::vector<Eigen::Matrix<float, 4, 4>, Eigen::aligned_allocator<Eigen::Matrix<float, 4, 4> > >::size_type {aka long unsigned int} | %ld [100%] Linking CXX shared module mycpp.cpython-39-x86_64-linux-gnu.so lto-wrapper: warning: using serial compilation of 2 LTRANS jobs lto-wrapper: note: see the ‘-flto’ option documentation for more information make[2]: Leaving directory '/mnt/e/wsl/foundationpose-main/mycpp/build' [100%] Built target mycpp make[1]: Leaving directory '/mnt/e/wsl/foundationpose-main/mycpp/build' Obtaining file:///mnt/e/wsl/foundationpose-main/bundlesdf/mycuda Preparing metadata (setup.py) ... done Installing collected packages: common Attempting uninstall: common Found existing installation: common 0.1.2 Uninstalling common-0.1.2: Successfully uninstalled common-0.1.2 DEPRECATION: Legacy editable install of common==0.0.0 from file:///mnt/e/wsl/foundationpose-main/bundlesdf/mycuda (setup.py develop) is deprecated. pip 25.3 will enforce this behaviour change. A possible replacement is to add a pyproject.toml or enable --use-pep517, and use setuptools >= 64. If the resulting installation is not behaving as expected, try using --config-settings editable_mode=compat. Please consult the setuptools documentation for more information. Discussion can be found at https://github.com/pypa/pip/issues/11457 Running setup.py develop for common error: subprocess-exited-with-error × python setup.py develop did not run successfully. │ exit code: 1 ╰─> [84 lines of output] /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/dist.py:289: UserWarning: Unknown distribution option: 'extra_cflags' warnings.warn(msg) /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/dist.py:289: UserWarning: Unknown distribution option: 'extra_cuda_cflags' warnings.warn(msg) running develop /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/cmd.py:90: DevelopDeprecationWarning: develop command is deprecated. !! ******************************************************************************** Please avoid running ``setup.py`` and ``develop``. Instead, use standards-based tools like pip or uv. By 2025-Oct-31, you need to update your project and remove deprecated calls or your builds will no longer be supported. See https://github.com/pypa/setuptools/issues/917 for details. ******************************************************************************** !! self.initialize_options() WARNING: Ignoring invalid distribution -ommon (/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages) Obtaining file:///mnt/e/wsl/foundationpose-main/bundlesdf/mycuda Installing build dependencies: started Installing build dependencies: finished with status 'done' Checking if build backend supports build_editable: started Checking if build backend supports build_editable: finished with status 'done' Getting requirements to build editable: started Getting requirements to build editable: finished with status 'error' error: subprocess-exited-with-error × Getting requirements to build editable did not run successfully. │ exit code: 1 ╰─> [19 lines of output] Traceback (most recent call last): File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 389, in <module> main() File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 373, in main json_out["return_val"] = hook(**hook_input["kwargs"]) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 157, in get_requires_for_build_editable return hook(config_settings) File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 473, in get_requires_for_build_editable return self.get_requires_for_build_wheel(config_settings) File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 331, in get_requires_for_build_wheel return self._get_build_requires(config_settings, requirements=[]) File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 301, in _get_build_requires self.run_setup() File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 512, in run_setup super().run_setup(setup_script=setup_script) File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 317, in run_setup exec(code, locals()) File "<string>", line 12, in <module> ModuleNotFoundError: No module named 'torch' [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. error: subprocess-exited-with-error × Getting requirements to build editable did not run successfully. │ exit code: 1 ╰─> See above for output. note: This error originates from a subprocess, and is likely not a problem with pip. Traceback (most recent call last): File "<string>", line 2, in <module> File "<pip-setuptools-caller>", line 35, in <module> File "/mnt/e/wsl/foundationpose-main/bundlesdf/mycuda/setup.py", line 21, in <module> setup( File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/__init__.py", line 115, in setup return distutils.core.setup(**attrs) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/core.py", line 186, in setup return run_commands(dist) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/core.py", line 202, in run_commands dist.run_commands() File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/dist.py", line 1002, in run_commands self.run_command(cmd) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/dist.py", line 1102, in run_command super().run_command(command) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/dist.py", line 1021, in run_command cmd_obj.run() File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/command/develop.py", line 39, in run subprocess.check_call(cmd) File "/root/anaconda3/envs/foundationpose/lib/python3.9/subprocess.py", line 373, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['/root/anaconda3/envs/foundationpose/bin/python', '-m', 'pip', 'install', '-e', '.', '--use-pep517', '--no-deps']' returned non-zero exit status 1. [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. Rolling back uninstall of common Moving to /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/common-0.1.2.dist-info/ from /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/~ommon-0.1.2.dist-info Moving to /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/common/ from /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/~ommon error: subprocess-exited-with-error × python setup.py develop did not run successfully. │ exit code: 1 ╰─> [84 lines of output] /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/dist.py:289: UserWarning: Unknown distribution option: 'extra_cflags' warnings.warn(msg) /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/dist.py:289: UserWarning: Unknown distribution option: 'extra_cuda_cflags' warnings.warn(msg) running develop /root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/cmd.py:90: DevelopDeprecationWarning: develop command is deprecated. !! ******************************************************************************** Please avoid running ``setup.py`` and ``develop``. Instead, use standards-based tools like pip or uv. By 2025-Oct-31, you need to update your project and remove deprecated calls or your builds will no longer be supported. See https://github.com/pypa/setuptools/issues/917 for details. ******************************************************************************** !! self.initialize_options() WARNING: Ignoring invalid distribution -ommon (/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages) Obtaining file:///mnt/e/wsl/foundationpose-main/bundlesdf/mycuda Installing build dependencies: started Installing build dependencies: finished with status 'done' Checking if build backend supports build_editable: started Checking if build backend supports build_editable: finished with status 'done' Getting requirements to build editable: started Getting requirements to build editable: finished with status 'error' error: subprocess-exited-with-error × Getting requirements to build editable did not run successfully. │ exit code: 1 ╰─> [19 lines of output] Traceback (most recent call last): File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 389, in <module> main() File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 373, in main json_out["return_val"] = hook(**hook_input["kwargs"]) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 157, in get_requires_for_build_editable return hook(config_settings) File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 473, in get_requires_for_build_editable return self.get_requires_for_build_wheel(config_settings) File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 331, in get_requires_for_build_wheel return self._get_build_requires(config_settings, requirements=[]) File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 301, in _get_build_requires self.run_setup() File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 512, in run_setup super().run_setup(setup_script=setup_script) File "/tmp/pip-build-env-_74yv_i8/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 317, in run_setup exec(code, locals()) File "<string>", line 12, in <module> ModuleNotFoundError: No module named 'torch' [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. error: subprocess-exited-with-error × Getting requirements to build editable did not run successfully. │ exit code: 1 ╰─> See above for output. note: This error originates from a subprocess, and is likely not a problem with pip. Traceback (most recent call last): File "<string>", line 2, in <module> File "<pip-setuptools-caller>", line 35, in <module> File "/mnt/e/wsl/foundationpose-main/bundlesdf/mycuda/setup.py", line 21, in <module> setup( File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/__init__.py", line 115, in setup return distutils.core.setup(**attrs) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/core.py", line 186, in setup return run_commands(dist) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/core.py", line 202, in run_commands dist.run_commands() File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/dist.py", line 1002, in run_commands self.run_command(cmd) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/dist.py", line 1102, in run_command super().run_command(command) File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/_distutils/dist.py", line 1021, in run_command cmd_obj.run() File "/root/anaconda3/envs/foundationpose/lib/python3.9/site-packages/setuptools/command/develop.py", line 39, in run subprocess.check_call(cmd) File "/root/anaconda3/envs/foundationpose/lib/python3.9/subprocess.py", line 373, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['/root/anaconda3/envs/foundationpose/bin/python', '-m', 'pip', 'install', '-e', '.', '--use-pep517', '--no-deps']' returned non-zero exit status 1. [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. 翻译一下,并告诉我这个故障的问题的是什么?
最新发布
07-27
<think>我们首先需要分析错误信息。从输出中可以看到,在安装common包(通过setup.py develop)时出现了错误。错误的核心是: ModuleNotFoundError: No module named 'torch' 这个错误发生在尝试构建editable模式时,具体是在获取构建可编辑模式所需的依赖时发生的。错误堆栈显示,在运行setup.py时,执行了一个字符串(可能是setup.py中的代码),其中第12行尝试导入torch,但失败了。 此外,还有关于setuptools的警告,指出使用`develop`命令已经过时,建议使用pip或uv等标准工具。 所以,问题的主要原因是:在构建过程中需要导入torch,但当前环境可能没有安装torch,或者安装的torch不可用。 另外,我们注意到在安装之前,尝试卸载了已有的common(0.1.2),然后安装当前路径下的版本(0.0.0),但失败了,之后回滚了卸载操作。 总结故障原因: 1. 构建过程中需要导入torch,但环境中没有安装torch,导致构建失败。 2. 使用过时的`setup.py develop`命令进行安装,而pip在将来会强制使用PEP517构建方式。 解决方案: 1. 确保环境中已经安装了torch。由于项目名为foundationpose,它可能是一个基于PyTorch的项目,因此需要安装PyTorch。 2. 建议使用pip的现代安装方式,避免直接使用setup.py。可以尝试使用`pip install -e .`,但要注意使用正确的环境。 另外,在输出中还有关于无效分发(Ignoring invalid distribution -ommon)的警告,可能是之前安装的common包在卸载后残留了部分文件,但暂时不影响主要问题。 因此,先尝试安装torch,然后再次运行安装命令。</think>### 编译错误分析及解决方案 **主要故障原因:** 1. **缺少PyTorch依赖**:核心错误是`ModuleNotFoundError: No module named 'torch'`,表明在构建CUDA模块时未检测到PyTorch安装 2. **过时的构建方式**:警告信息指出`setup.py develop`已弃用,建议使用PEP517标准构建 3. **无效的分发残留**:存在无效的common包残留(`Ignoring invalid distribution -ommon`) 4. **不兼容的构建参数**:`setup.py`中使用了过时的参数`extra_cflags/extra_cuda_cflags` **完整错误翻译:** ``` (在foundationpose环境中) 尝试安装本地CUDA模块时失败: - 检测到过时的构建方式警告(develop命令将在2025年弃用) - 尝试卸载旧版common包(0.1.2)后安装新版本(0.0.0) - 构建过程因缺少torch模块而失败: ModuleNotFoundError: No module named 'torch' - 回滚卸载操作,恢复common包 - 建议改用PEP517标准构建工具(pip/uv) ``` **解决方案步骤:** 1. **安装PyTorch依赖**: ```bash pip install torch torchvision torchaudio ``` 2. **使用现代构建方式**: ```bash pip install -e . --use-pep517 ``` 3. **清理无效分发**: ```bash pip uninstall -y common && pip cache purge ``` 4. **更新setup.py配置**: ```python # 移除过时参数 setup( name="common", # 删除 extra_cflags extra_cuda_cflags ext_modules=[CUDAExtension(...)] ) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值