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

C++11中私有构造类静态方法返回shared_ptr实例编译报错问题

问题背景

我希望禁止用户通过构造函数直接创建类实例,因此将构造函数标记为私有方法。同时需要提供一个方法,返回可以自动管理实例生命周期的对象,最初设计的该方法为getFoo()。

初版代码

#include <iostream>
#include <memory>
 
class Foo : public std::enable_shared_from_this<Foo> {
private:     // 禁止用户直接通过构造函数创建实例                    
    Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }
public:
    ~Foo() { std::cout << "Foo::~Foo\n"; } 
    std::shared_ptr<Foo> getFoo() { return shared_from_this(9); }
private:
    int num_;
};

由于构造函数设为私有后,没有任何途径可以创建类实例,getFoo方法永远无法被调用,因此对代码做了修改。

修改后无法编译的代码

#include <iostream>
#include <memory>
 
class Foo : public std::enable_shared_from_this<Foo> {
private:     // 禁止用户直接通过构造函数创建实例                    
    Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }
public:
    ~Foo() { std::cout << "Foo::~Foo\n"; } 
    static std::shared_ptr<Foo> Create() { return std::make_shared<Foo>(5); }
private:
    int num_;
};
 
int main() {
    auto pf = Foo::Create(); 
}

编译报错核心信息:

error: 'Foo::Foo(int)' is private within this context
  119 |       ::new((void*)__p) _Tp(std::forward<_Args>(__args)...);
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:6:5: note: declared private here
    6 |     Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }
      |     ^~~

原本认为类的所有成员函数都有权限访问类的私有成员,不清楚错误原因,且开发环境仅支持C++11标准。初步猜测是因为Create()是静态函数,无权调用非静态的构造函数,但不确定该判断是否正确。


问题解答

你的猜测不成立。静态成员函数拥有和普通成员函数完全一致的类私有成员访问权限,编译报错的核心原因是:实际调用Foo私有构造函数的代码不是Create()本身,是标准库中std::make_shared的内部实现——这段代码不属于Foo类的成员范畴,自然没有访问Foo私有成员的权限。

C++的访问控制校验只看「执行访问操作的代码所在的作用域」,不会因为外层调用方是类成员,就给嵌套调用的、不属于类的外部代码开放私有访问权限。

C++11 兼容的解决方案

不使用std::make_shared,直接在类成员函数内部手动构造实例再交给shared_ptr管理即可,此时构造Foo实例的代码位于Create()作用域内,可以正常访问私有构造函数:

#include <iostream>
#include <memory>
 
class Foo : public std::enable_shared_from_this<Foo> {
private:                    
    Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }
public:
    ~Foo() { std::cout << "Foo::~Foo\n"; } 
    static std::shared_ptr<Foo> Create() { 
        return std::shared_ptr<Foo>(new Foo(5)); 
    }
private:
    int num_;
};
 
int main() {
    auto pf = Foo::Create(); 
}

方案说明

  • 该实现完全符合C++11标准,不需要更高版本语法支持
  • 相比std::make_shared会存在一次额外的控制块内存分配开销,但可以完美解决私有构造函数的访问权限问题
  • 禁止用户直接构造实例的需求完全满足:外部代码无法调用私有构造函数,只能通过Create()方法获取托管的实例指针

补充:如果后续可以升级到C17及以上版本,还可以通过自定义分配器实现和make_shared一致的单次内存分配效果,但C11环境下上述写法是兼容性、可读性最均衡的实现。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 11:30:55