英文:
Temporarily assign an arbitrary value to a pointer
问题
我定义一个指向任意类型的指针:`A* p`。
**我想以后再进行赋值,但只在我最初知道条件的情况下。**
### 带有布尔变量的基本解决方案
```c++
A* p;
bool assign_p = condition; // 最初
p = assign_p ? new A : NULL; // 后来
然而,我想避免使用额外的变量(布尔变量)以节省空间,因为这个过程会在大型数组上发生。那么我的问题是:我可以将指针用作临时布尔值吗?
使用任意指针值的解决方案?
A *p = condition ? (A*) 1 : NULL; // 最初
p = p ? new A : NULL; // 后来
这只使用一个变量(指针),但是将(A*) 1
分配给它是否安全且符合良好实践,尽管它指向空处?
使用联合体的解决方案?
union boolA { bool assign; A* p; };
boolA P = {condition}; // 最初
P.p = P.assign ? new A : NULL; // 后来
这也只使用了指针所需的内存,并且本质上与上面的解决方案相同,也许是一种更好的方式?
但是我对于联合体引发的未定义行为有些困惑。在这方面是安全的吗?此外,如果我需要许多这些指针,将它们做成联合体数组是否符合良好实践?
其他解决方案?
<details>
<summary>英文:</summary>
Say I define a pointer to whatever type: `A* p`.
**I want to assign it later, but only with a condition that I know initially.**
### Basic solution with a boolean
```c++
A* p;
bool assign_p = condition; // initially
p = assign_p ? new A : NULL; // later
However, I would like to avoid using an extra variable (the boolean) in order to save space, as this process happens over large arrays. My question is then: can I use the pointer as a temporary boolean?
Solution with an arbitrary pointer value?
A *p = condition ? (A*) 1 : NULL; // initially
A *p = p ? new A : NULL; // later
This uses only 1 variable (the pointer), but is it safe and good practice to assign (A*) 1
even though it points nowhere?
Solution with an union?
union boolA { bool assign; A* p; };
boolA P = {condition}; // initially
P.p = P.assign ? new A : NULL; // later
This should also use only the memory necessary for the pointer, and essentially does the same as the solution above, maybe in a better way?
But I am a bit confused concerning the undefined behaviors occurring with unions. Is it safe in this respect? Furthermore, is it a good practice to make arrays of unions if I need to have many of these pointers?
Other solution?
答案1
得分: 6
这可以通过使用一个“sentinel”(实际值,以特殊方式解释,类似于数字-1经常用于指示搜索函数中的“未找到”)以安全的方式解决。创建一个单一的A
实例(其成员设置为任意但安全的值,例如全部为零和null),将其存储为A * sentinel
,并将“true”数组元素设置为sentinel
。当您准备分配真实对象时,您只需将数组元素与sentinel
进行比较。
英文:
This could be solved in a safe way by using a sentinel (an actual value that is interpreted in a special way, similar to how the number -1 is often used to indicate "not found" in search functions). Create a single instance of A
(with its members set to arbitrary but safe values, e.g. all zeroes and nulls), store it as A * sentinel
, and set the "true" array elements to sentinel
. When you are ready to allocate the real objects, you can just compare the array elements to sentinel
.
答案2
得分: 3
许多系统将没有实际指针的值低于某个截止值(例如0x10000),因此您可以完全以不同的方式处理截止值以上和以下的值。
其中一个例子是Windows,截止值以下的值将被许多与窗口相关的函数视为资源值,而截止值以上的值将是字符串指针(根据调用的函数而定,可以是char或wchar_t)。
我认为一个函数可以以完全不同的方式处理0、1和大于0x10000的值,这没有问题。
英文:
Many systems will have no actual pointers with values lower than some cut-off (0x10000 for example), and you can therefore treat values above and below that cut-off in entirely different manners.
One example of this is windows, where values below the cut-off will be treated as resource values by many window-related functions, while values above that will be string pointers (either char or wchar_t depending on the function being invoked).
I see no problem with a function that treats 0, 1 and values above 0x10000 in entirely different ways.
答案3
得分: 0
sentinel
前面提到的是一个不错的解决方案,但如果您难以找到适用于对象A
的这种值,我认为std::optional<A*>
也可能是一个不错的解决方案。您可以有三种状态 -
std::nullopt
- 可选项尚未初始化*opt = nullptr
- 可选项已初始化,但值为nullptr
(因为条件未满足)*opt = a
- 可选项已初始化为正确的值(条件满足)。
我认为主要优势在于前两个选项具有不同的状态,这对于将来可能需要的进一步逻辑以及调试目的可能非常有用。与sentinel相比,它更清晰,因为没有未来的阅读者\开发者需要记住\跟踪\检查的"特殊值"。
如果std::optional
对您来说太"重",因为数组中有大量元素等,您也可以使用A**
,并拥有类似的三种情况(ptr = nullptr
,*ptr = nullptr
,**ptr = a
)。
英文:
sentinel
suggested earlier is a fine solution, but if you struggle to find such value for your object A
, I think std::optional<A*>
may also be a good solution for that. You can have three states -
std::nullopt
- The optional is not yet initialized*opt = nullptr
- The optional has been initialized, but withnullptr
(since the condition wasn't satisfied)*opt = a
- The optional was initialized with a proper value (the condition is satisfied).
I think the main advantage is having different states for the first two options, which may be very useful for further logic you may need in the future, and for debugging purposes. It is also more clean than sentinel, since there's no "special value" the future reader\developer needs to remember\keep track of\check at every usage.
If std::optional
is "heavy" for you, since you have lots of elements in the array etc, you can use A**
as well, and have analog three cases (ptr = nullptr
, *ptr = nullptr
, **ptr = a
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论