c++ - C ++:如何创建“条件”构造函数/避免在赋值时破坏?
问题描述
让我们从一些示例代码开始:
class Shader {
public:
static absl::StatusOr<Shader> Create(const std::string &vertexShaderFile, const std::string &fragmentShaderFile) {
ASSIGN_OR_RETURN(GLuint vertexShader, gl::createShader(GL_VERTEX_SHADER, readFile(vertexShaderFile)))
ASSIGN_OR_RETURN(GLuint fragmentShader, gl::createShader(GL_FRAGMENT_SHADER, readFile(fragmentShaderFile)))
Shader s;
glAttachShader(s._programId, vertexShader);
glAttachShader(s._programId, fragmentShader);
RETURN_IF_ERROR(gl::linkProgram(s._programId));
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
std::cerr << "AAA" << std::endl;
return s;
}
void use() const {
std::cerr << "use " << _programId << std::endl;
glUseProgram(_programId);
}
~Shader() {
std::cerr << "destruct!" << std::endl;
glDeleteProgram(_programId);
}
private:
explicit Shader() : _programId(glCreateProgram()) {}
GLuint _programId{0};
};
用法:
const auto &_statusOr4 = (Shader::Create("resources/vertex.glsl", "resources/frag.glsl"));
if (!_statusOr4.ok())return _statusOr4.status();
Shader shader = *_statusOr4;
std::cerr << "BBB" << std::endl;
这将打印:
AAA
destruct!
BBB
我认为s
inShader::Create
被复制到一个新对象,然后旧对象被破坏,这调用了~Shader
析构函数。
我想避免复制+破坏。
我不能将所有Create
代码都扔到 c'tor 中,因为有一些操作可能会失败。
我怎样才能做到这一点?
添加
Shader(const Shader&) = delete;
Shader& operator=(const Shader&) = delete;
阻止该程序编译。这很好,因为这确实是一个错误,但是我仍然不知道如何编写这样的Create
方法(没有将所有内容移入构造函数并引发异常)
我试图添加一个移动构造函数:
Shader(Shader&& o) noexcept : _programId(o._programId){
std::cerr << "move ctor" << std::endl;
}
必须更改作业以使其成为参考:
const auto &_statusOr4 = (Shader::Create("resources/vertex.glsl", "resources/frag.glsl"));
if (!_statusOr4.ok()) return _statusOr4.status();
const Shader& shader = *_statusOr4;
我认为应该没问题,因为_statusOr4
它们的寿命相同。
但是....现在我明白了
AAA
move ctor
destruct!
BBB
似乎析构函数仍然在它被“移出”的对象上被调用。
StatusOr
来自Abseil
解决方案
我想避免复制+破坏。
通常,当您的函数返回类型与您返回的变量类型匹配时,您无需执行任何操作。没有复制,也没有破坏发生。阅读有关复制省略的内容。
在您的情况下,您构造Shader
但返回absl::StatusOr<Shader>
。所以有两个不同的对象:s
函数中的局部变量和返回值。它们属于不同的类型,因此编译器无法使它们成为相同的东西,您将看到s
被调用的析构函数。但是,如果您Shader
正确编写,这是无害的。支持移动构造,并且s
会被移动到返回值,留下一个容易破坏的空壳。仍然没有复制。
假设 0 是无效/空着色器程序并且glDeleteProgram(0)
本质上是无操作的,则移动构造函数可能如下所示:
Shader(Shader&& other) {
_programId = other._programId;
other._programId = 0;
}
您不想随意复制对象Shader
objects,否则您最终会 _programId
多次删除相同的对象。为避免这种情况,请将复制构造函数和复制赋值运算符标记为delete
.
我不能把所有的 Create 代码都扔到 c'tor 中,因为有一些操作可能会失败。
这就是例外的原因。
推荐阅读
- node.js - 在 sqlite3(节点包)中,如何按顺序运行多个查询?
- python - 将下载的 Python 的路径添加到 Visual Studio Code
- python - 在 Windows 10 上运行软件时禁用通知
- python - 合并日期上具有不同值的多个数据框
- r - 有没有办法增加系统发育树中允许的物种数量以供我分析?
- bioconductor - clusterProfiler 无法加载包
- google-apps-script - 创建自定义函数以通过 App 脚本验证 Google 电子表格中的数据
- linker-errors - 链接错误 libbfd:在 RHEL8(64 位)上构建 32 位应用程序时
- javascript - Javascript:操作数组以返回最短节点
- javascript - 在鼠标悬停时显示名称