【问题标题】:C++11 way to reset a struct to null?C ++ 11将结构重置为null的方法?
【发布时间】:2018-06-14 00:32:52
【问题描述】:

我正在学习一个物理库,它涉及创建信息结构,然后将它们传递给初始化函数:

btRigidBodyConstructionInfo rbInfo = (/*values...*/);
btRigidBody* rigidBody = new btRigidBody(rbInfo);

现在我想重置结构(将其设为空)以重用它。我在 SO 上发现了另一个相同的问题,答案是创建一个零初始化的临时变量并将其设置为它,或者在 C++11 之后:

rbInfo = {};

当我尝试这个时,我得到了消息:

"没有运算符 "=" 匹配这些操作数。

我很困惑,但后来发现这种语法试图调用默认构造函数(至少在我的编译器中(Visual Studio 2017)),而 rbInfo 没有。我感觉该语法与以下内容相同:

rbInfo = btRigidBodyConstructionInfo{};

在这种情况下,如果不设置单个成员,就没有办法重置结构吗?我考虑过 memsetting,但这通常是个坏主意,因为可能存在诸如 vtable 指针之类的东西,对吧?

【问题讨论】:

  • 如果你的类有一个合理的“空”状态,为什么不实现一个默认构造函数呢?
  • @VTT 我很确定这是隐式默认构造对象的正确语法。
  • @VTT I'm not ;)
  • 如果你的类没有默认构造函数,你所说的“reset”是什么意思?要重置任何东西,必须有一个关于最终状态的规范——实际上,这通常意味着与默认构造对象相同的状态。如果没有默认构造函数,需要指定需要的结束状态,
  • @Zebrafish - 是的,设计上没有安全的方法。如果需要以某种方式初始化类型,通常是有原因的。该语言本身不允许您默认初始化某些内容,除非它显式或隐式地支持它。

标签: c++ c++11 reset zero bullet


【解决方案1】:

在 C++ 中,变量具有支持它们的值,而不是引用。这与大多数其他语言不同,其中变量是对可能值的引用。

有些语言的简单数据是实际值,而类总是引用。很少有语言有类对象,其变量实际上是类的值。

(所有种类的)值没有通用的“空”状态。通常,值不是“可空的”。在 C++ 中,您可以强制类型永远不会保存 0 的字节值。例如:

class Foo {
  Foo(){}
private:
  int x = -1;
};

这个非常简单的类永远不可能将其x 值设为0

对于某些类型的值,您可以将它们完全归零(将它们的所有字节设置为零)。对于其他类型的值,这是明确不允许的。

类似于可空的概念是从零参数构造的。如果是这种情况,并且您有一个复制或移动分配运算符,那么

foo = {};

将(通常)分配给foo 一个临时的零参数构造Foo(假设foo 的类型为Foo,并且理智的operator= 重载)。

如果您的类型btRigidBodyConstructionInfo 没有零参数构造函数,并且不是聚合,那么如果foobtRigidBodyConstructionInfo foo;,则您不能执行foo = {};

你可以做foo = {construction arguments};,假设一个理智的operator=它会做你想做的。

如果您想要一个可为空的值类型,请考虑boost::optionalstd::optional

std::optional<btRigidBodyConstructionInfo> foo{ std::in_place, /*values...*/ };

然后在使用点使用*foo。稍后,您可以通过 foo={}; 将该值设为空。

要重新填充它,您可以使用

foo = {std::in_place, /*values...*/};

foo.emplace( /*values...*/ );

您可以通过执行if (!foo) 来测试foo 是否为空,并且您可以通过*foo 访问该值(如果为空,则为未定义的行为)。

这有点像指针,但它实际上是一个值类型。

【讨论】:

    【解决方案2】:

    你的问题听起来有点像小XY problem

    你说你的目标是

    现在我想重置结构(将其设为空)以重用它。

    X 是“重用结构”,但不知何故混入了“重置结构”的 Y。如果您只想重用结构,你可以这样做:

    btRigidBodyConstructionInfo rbInfo = (/*values...*/);
    btRigidBody* rigidBody = new btRigidBody(rbInfo);
    
    rbInfo = {/*new values...*/};
    

    或者,如果您的编译器太旧而无法支持该语法,那么:

    rbInfo = btRigidBodyConstructionInfo(/*new values...*/);
    

    【讨论】:

    • rbInfo = {/* 新值...*/};似乎是最简单的。是的,我明白你的意思,但我很好奇该语言是否有任何语法可以使已经创建的结构无效,因为这种语言中似乎有很多隐藏的小功能,而且每隔一段时间就会添加一些东西几年了,我总是迟到。
    • @Zebrafish 如果构造函数没有参数,则它是“默认构造函数”。 Foo foo{}; 必须调用Foo的默认构造函数,因为它不提供参数
    • @Zebrafish 在一般情况下,在 C++ 中,类对象成员的空值(如字面上将它们归零)几乎没有意义。类的主要特性之一是支持invariants(始终使类处于某种已定义的、一致的状态)。明确归零会明显违背这一点。
    • @Zebrafish 不,他们做的事情并没有完全不同;事实上,他们做同样的事情。 (){},当作为初始化器有效时,都为内置类型执行 值初始化:,这意味着零初始化。对于类,这意味着调用默认 ctor。
    • 您可能对聚合初始化感到困惑,这是list initialization 的一个特例,形式为Foo foo {}(或Foo foo = {}),但这是一个语句 , 不是表达式
    猜你喜欢
    • 1970-01-01
    • 2016-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多