假设我定义了一个指向任何类型的指针:A* p
.我想以后再赋值,但只在我最初知道的条件下赋值。
布尔型的基本解决方案
A* p;
bool assign_p = condition; // initially
p = assign_p ? new A : NULL; // later
然而,为了保存空间,我想避免使用额外的变量(布尔值),因为这个过程发生在大型数组上。我的问题是:我可以使用指针作为临时布尔值吗?
任意指针值的解决方案?
A *p = condition ? (A*) 1 : NULL; // initially
A *p = p ? new A : NULL; // later
这只使用了一个变量(指针),但是即使它没有指向任何地方,也分配(A*) 1
是安全和良好的做法吗?
有工会的解决方案?
union boolA { bool assign; A* p; };
boolA P = {condition}; // initially
P.p = P.assign ? new A : NULL; // later
这也应该只使用指针所需的内存,本质上与上面的解决方案相同,也许是更好的方式?但我对工会发生的未定义行为有点困惑。在这方面安全吗?此外,如果我需要有许多这样的指针,那么制作联合数组是一个好的实践吗?
3条答案
按热度按时间pkln4tw61#
这可以通过使用 sentinel(以特殊方式解释的实际值,类似于数字-1通常用于指示搜索函数中的“未找到”)以安全的方式解决。创建一个
A
示例(将其成员设置为任意但安全的值,例如所有零和空值),将其存储为A * sentinel
,并将“true”数组元素设置为sentinel
。当你准备好分配真实的对象时,你可以将数组元素与sentinel
进行比较。kfgdxczn2#
许多系统都没有实际的指针,其值低于某个截止值(例如0x10000),因此您可以以完全不同的方式处理高于和低于该截止值的值。
一个例子是windows,其中低于截止值的值将被许多与窗口相关的函数视为资源值,而高于截止值的值将被视为字符串指针(char或wchar_t,取决于被调用的函数)。
我认为一个以完全不同的方式处理0、1和0x10000以上的值的函数没有问题。
du7egjpx3#
前面提出的
sentinel
是一个很好的解决方案,但是如果你很难为你的对象A
找到这样的值,我认为std::optional<A*>
也可能是一个很好的解决方案。你可以有三种状态-std::nullopt
-尚未初始化可选*opt = nullptr
-已经初始化了可选的,但是使用了nullptr
(因为不满足条件)*opt = a
-已使用正确的值初始化可选值(满足条件)。我认为主要的优点是前两个选项具有不同的状态,这对于您将来可能需要的进一步逻辑以及调试目的可能非常有用。它也比sentinel更干净,因为未来的读者/开发人员在每次使用时都不需要记住“跟踪”检查的“特殊值”。
如果
std::optional
对你来说很“重”,因为你在数组中有很多元素,你也可以使用A**
,并模拟三种情况(ptr = nullptr
,*ptr = nullptr
,**ptr = a
)。