Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何定义一个只能在栈上生成对象的类 #112

Open
Mq-b opened this issue Oct 15, 2023 · 3 comments
Open

如何定义一个只能在栈上生成对象的类 #112

Mq-b opened this issue Oct 15, 2023 · 3 comments

Comments

@Mq-b
Copy link

Mq-b commented Oct 15, 2023

你们描述的是:

方法:将 new 和 delete 重载为私有

事实上在我看来毫无价值,你设置私有,那我不让它优先查找内部的不就是,加有限定名字查找 :: 优先查找全局的 operator newoperator delete 不就是。

除了逆天的 msvc 有限定名字查找有问题,gccclang 都可以直接使用。code运行

#include <iostream>

struct X{
    int n{};
    X() { puts("X()"); }
    X(int v):n{v} {puts("X(int)");}
    ~X() { puts("~X()"); }
private:
    void* operator new(size_t)noexcept {return nullptr;}
    void operator delete(void*) {}
};

int main(){
    X* p = ::new X(10);
    std::cout<< p->n <<'\n';
    ::delete p;
}
@frederick-vs-ja
Copy link

frederick-vs-ja commented Oct 15, 2023

另外,这个方法根本限制不了在创建静态或线程局部存储期的该类对象。实现中这些存储期的对象都不在栈上。

务必要注意:如果允许通过一个接口构造或按值返回该类的对象,那么用户就可以在堆上动态分配一块存储(使用 malloc::operator new),并用原位布置 new 把对象构造到堆上(如 ::new ((void*)p) T{args})。


一些近似的办法,但相当可能不符合题意:

  1. 完全限制该类的构造函数的访问,使得外部不得构造该类对象,而内部操作只在栈上构造该类对象。
  2. 生成不可移动或复制的 lambda 表达式闭包类型(需要至少 C++17)。
struct Pinned {
    Pinned() = default;
    Pinned(const Pinned&) = delete;
    Pinned& operator=(const Pinned&) = delete;
};

int main()
{
    auto pinned_lambda = [p = Pinned{}]{};
    // 此后不能在其他地方构造另一个与 pinned_lambda 拥有相同类型的对象
}

个人认为完全符合题目本意的做法基本上是不存在的,除非通过和操作系统交流,在构造函数中确定 this 是否指向系统划定的栈空间。

@SainoNamkho
Copy link

SainoNamkho commented Oct 15, 2023

  1. 完全限制该类的构造函数的访问,使得外部不得构造该类对象,而内部操作只在栈上构造该类对象。

这种方法可能不太行

struct X {
    static X construct() { return {}; }
private:
    X() = default;
};

struct Y : X {
    Y() : X{X::construct()} {}
};

int main()
{
    X* px1 = new Y;
    X* px2 = new (operator new(sizeof(X))) X(X::construct());
}

@frederick-vs-ja
Copy link

  1. 完全限制该类的构造函数的访问,使得外部不得构造该类对象,而内部操作只在栈上构造该类对象。

这种方法可能不太行

struct X {
    static X construct() { return {}; }
private:
    X() = default;
};

struct Y : X {
    Y() : X{X::construct()} {}
};

int main()
{
    X* px1 = new Y;
    X* px2 = new (operator new(sizeof(X))) X(X::construct());
}

这个例子仍然相当于允许在外部构造该类对象。我指的是任何能创建该类对象的函数都不能被外部调用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants