使用std::shared_ptr不允许编译时评估、计算、内联和其他优化。这可能是由于多线程安全。
因此,我尝试了我自己的简单智能指针,只是为了看看什么是可能的,如果线程安全是不需要的。这只是一个侵扰性的、链接的列表引用跟踪智能指针的最小草案(更多信息请参见示例中的注释)。
问题:
~myptr())。为什么?https://godbolt.org/z/1xK1r4YjT
#include <memory>
//#include <iostream>
// Simplistic linked list reference tracking smart pointer.
//
// Linking instead of reference counting is interesting because it allows for extra functionality such as
// moving around referenced memory blocks (growable objects, defragmentation), "set null"
// semantics on delete, etc.
//
// Not thread safe, but (trying to) support a high level of compile time evaluation, inlining,
// optimization.
template<typename T>
struct myptr {
private:
T * p;
myptr * next;
public:
constexpr myptr(T * p) noexcept : p(p), next(p ? p->first : nullptr) {
p->first = this;
}
constexpr myptr(const myptr & other) noexcept : myptr(other.p) {}
constexpr T &operator*() {
return *p;
}
constexpr T *operator->() {
return p;
}
T &operator=(const myptr & other) = delete;
T &operator=(const myptr && other) = delete;
constexpr ~myptr() noexcept {
if (p) {
// We must remove `this` from the list. As these are typically stack references, they will be
// mostly LIFO, so we will typically find it immediately.
#if 1
myptr ** pnext = &(p->first);
while (*pnext) {
if (*pnext == this) {
// Found our smart pointer, bypass.
*pnext = next;
break;
}
pnext = &((*pnext)->next);
}
#else
// NOTE: the loop with null check (above) should not be necessary, as the invariant of myptr holds
// that we will always find `this` in the list and never hit a null pointer.
// However, if we use the code below, clang will immediately stop compile time evaluation.
// Is there some "function with potential null pointer fault" restriction in play?
myptr ** pnext = &(p->first);
while (*pnext != this) {
pnext = &((*pnext)->next);
}
// Bypass.
*pnext = next;
#endif
next = nullptr;
if (!p->first) {
// The last reference vanished.
delete p;
}
p = nullptr;
}
}
};
struct Obj {
int i{20};
inline ~Obj() noexcept {
i = -1;
//std::cout << "destructor" << std::endl;
}
private:
// intrusive linked references list
struct myptr<Obj> * first{};
friend struct myptr<Obj>;
};
// Try different pointers:
using obj_ptr = myptr<Obj>;
//using obj_ptr = std::shared_ptr<Obj>;
//using obj_ptr = Obj*;
//constexpr
inline
int fun(obj_ptr obj) {
return obj->i;
}
int main() {
obj_ptr obj(new Obj);
{ obj_ptr obj2(obj);
obj2->i += 1;
}
obj_ptr obj3(obj);
obj3->i *= 2;
return fun(obj);
}发布于 2021-07-01 19:20:46
下面的示例在clang上编译为完整的编译时间评估。关于gcc,情况并非如此。为什么?
因为这两种行为都不是必需的。constexpr并不意味着“函数将在编译时执行”。这意味着编译器可以在编译时进行这样的评估.只有在必须计算为常量表达式的上下文中调用该函数时,才需要该函数。
你在这里可不是这么做的。
您在Clang上看到的优化与constexpr限定符无关。把那些限定符拿走,然后Clang仍在优化它。它们只是常规的编译器优化。
clang确实计算了所有的编译时间,如果并且只有当包含了一些空指针检查(请参见~myptr())时。为什么?
编译器优化是挑剔的,有时非常武断。
https://stackoverflow.com/questions/68214215
复制相似问题