如何在创建对象时使用std::optional进行错误处理而不立即破坏它们? 错误处理是C++构造函数中的一个挑战。有几种常见的方法,但它们都有明显的缺点。例如,抛出异常可能会导致在构造函数的早期泄漏已分配的资源,使其成为一种容易出错的方法。使用静态init()方法是另一种常见的解决方案,但它违背了RAII原则

如何在创建对象时使用std::optional进行错误处理而不立即破坏它们? 错误处理是C++构造函数中的一个挑战。有几种常见的方法,但它们都有明显的缺点。例如,抛出异常可能会导致在构造函数的早期泄漏已分配的资源,使其成为一种容易出错的方法。使用静态init()方法是另一种常见的解决方案,但它违背了RAII原则,c++,error-handling,constructor,c++17,stdoptional,C++,Error Handling,Constructor,C++17,Stdoptional,研究这个主题,我找到了答案,并建议使用名为std::optional的C++17特性,我发现它很有希望。然而,这种解决方案似乎有一个潜在的问题——当用户检索对象时,它会立即触发析构函数 下面是一个简单的代码示例,描述了这个问题,我的代码基于上述源代码 A类 { 公众: A(int myNum); ~A(); 静态std::可选make(int myNum); bool isBuf(){return\u buf;}; 私人: char*_buf; }; std::可选A::make(int myN

研究这个主题,我找到了答案,并建议使用名为
std::optional
的C++17特性,我发现它很有希望。然而,这种解决方案似乎有一个潜在的问题——当用户检索对象时,它会立即触发析构函数

下面是一个简单的代码示例,描述了这个问题,我的代码基于上述源代码

A类
{
公众:
A(int myNum);
~A();
静态std::可选make(int myNum);
bool isBuf(){return\u buf;};
私人:
char*_buf;
};
std::可选A::make(int myNum)
{
std::cout您的类违反了

为复制构造函数插入指令并简化
main
,以获得以下结果:

#include <optional>
#include <iostream>

class A
{
public:
    A(int myNum);
    ~A();
    A(const A& other){
        std::cout << "COPY!\n";
    }
    static std::optional<A> make(int myNum);
    bool isBuf() { return _buf; };
private:
    char* _buf = nullptr;
};

std::optional<A> A::make(int myNum)
{
    std::cout << "A::make()\n";
    if (myNum < 8)
        return {};
    return A(myNum);
}

A::A(int myNum)
{
    std::cout << "A()\n";
    _buf = new char[myNum];
}

A::~A()
{
    std::cout << "~A()\n";
    delete[]_buf;
}

int main()
{
    
    std::optional<A> a = A::make(42);
    std::cout << "main finished\n";
}
调用
A::make()
时,本地
A(myNum)
被复制到retunred
optional
中,然后调用其析构函数。如果没有
std::optional
(例如通过值返回
A
),也会出现同样的问题

我添加的复制构造函数不会复制任何内容,但编译器生成的构造函数会对
char*\u buf;
成员进行浅层复制。由于没有正确地深度复制缓冲区,它会被删除两次,从而导致运行时错误

对0规则使用
std::vector
,或正确实现3/5规则。您的代码调用未定义的行为


PS与问题没有直接关系,但您应该初始化成员,而不是在构造函数体中为其赋值。更改:

A::A(int myNum)
{
    std::cout << "A()\n";
    _buf = new char[myNum];
}
A::A(int myNum)
{

std::cout在我看来像是违反了。您复制了一个
a
,两个实例都试图删除同一个指针。Edit:看起来像是将
返回a(myNum);
更改为
返回{myNum};
隐藏了问题,因此可能是3/5/0错误规则。您被告知错误。对于构造函数中的错误处理并不常见。构造函数中错误处理本身并没有C++程序的任何其他部分更复杂。只要致命错误导致正确抛出异常,C++将自动处理所有低级细节,例如破坏已构建的类成员。(按相反顺序)等…使用正确的工具来完成正确的工作。一个构建失败只是通过抛出一个异常来报告。你知道什么是异常以及如何使用它们吗?我知道什么是异常好吧…我只是试图通过错误地使用它们来学习新事物。lol。在花了一整天的时间在这个可选的废话上之后,我只是使用异常并移动了尽管如此,我还是决定问,在这里我学习了3/5/0的规则……谢谢你们两个忘了将
\u buf
设置为
nullptr
?在复制的情况下删除什么?@Red.Wave?“忘了将\u buf
初始化为
nullptr
,以将其显式设置为副本中的某个内容(请注意,我的副本构造函数仅用于说明,而不是实际复制任何内容)在我的副本中,没有什么被删除,因为<代码> 是关于PPS的代码> NulLPTR <代码>,我指的是使用原始指针,当我声称抛出异常会导致泄漏。我知道C++中使用原始指针不是一个好的实践,但是我不能忽视它是可能的…@ ZeNIR,但是如果你想使用原始拥有指针,那么THHT是PRO。没有什么是不能避免的
A::make()
A()
COPY!
~A()
main finished
~A()
A::A(int myNum)
{
    std::cout << "A()\n";
    _buf = new char[myNum];
}
A::A(int myNum) : _buf( new char[myNum])
{
    std::cout << "A()\n";
}