在 C++如果返回一个指针并立即取消引用,这两个操作是否会被优化掉?
在 C++ 中,如果我获取并返回变量的地址,然后调用者立即取消引用它,编译器是否会可靠地优化这两个操作?
我问的原因是我有一个数据结构,其中使用类似于 std::map 的接口,其中 find() 返回指向值的指针(迭代器),并返回 NULL (没有简单的 .end() 等效项) ) 表示尚未找到该值。
我碰巧知道存储的变量是指针,因此即使我直接返回值,返回 NULL 也可以正常工作,但似乎返回指向该值的指针更通用。否则,如果有人试图在那里存储实际上为 0 的 int,数据结构会声称它不存在。
然而,我想知道这里是否有任何效率损失,因为编译器应该优化掉那些只是撤销彼此影响的操作。问题是两者被函数返回分隔开,所以它可能无法检测到它们只是相互撤消。
最后,拥有一个仅返回值的私有成员函数和一个仅获取值的地址的内联公共成员函数怎么样?那么至少地址/取消引用操作会一起发生,并且有更好的机会被优化,而 find() 函数的整个主体不是内联的。
private: V _find(key) { ... // a few dozen lines... } public: inline V* find(key) { return &_find(key); } std::cout << *find(a_key);
这将返回一个指向临时对象的指针,这是我没有想到的。唯一可以做的与此类似的事情就是在 _find() 中进行大量处理并在 find() 中完成最后一步和指针的返回,以最大限度地减少内联代码量。
private:
W* _find(key) {
... // a few dozen lines...
}
public:
inline V* find(key) {
return some_func(_find(key)); // last steps on W to get V*
}
std::cout << *find(a_key);
或者正如另一位响应者提到的,我们可以在原始版本中返回对 V 的引用(再次,不确定为什么我们乍一看对这些琐碎的事情都视而不见......请参阅讨论。)
private:
V& _find(key) {
... // a few dozen lines...
}
public:
inline V* find(key) {
return &_find(key);
}
std::cout << *find(a_key);
In C++ if I get and return the address of a variable and the caller then immediately dereferences it, will the compiler reliably optimize out the two operations?
The reason I ask is I have a data structure where I'm using an interface similar to std::map where find() returns a pointer (iterator) to a value, and returns NULL (there is no trivial .end() equivalent) to indicate that the value has not been found.
I happen to know that the variables being stored are pointers, so returning NULL works fine even if I returned the value directly, but it seems that returning a pointer to the value is more general. Otherwise if someone tried to store an int there that was actually 0 the data structure would claim it isn't there.
However, I'm wondering if there's even any loss in efficiency here, seeing as the compiler should optimize away actions that just undo the effect of each other. The problem is that the two are separated by a function return so maybe it wouldn't be able to detect that they just undo each other.
Lastly, what about having one private member function that just returns the value and an inline public member function that just takes the address of the value. Then at least the address/dereference operations would take place together and have a better chance of being optimized out, while the whole body of the find() function is not inlined.
private: V _find(key) { ... // a few dozen lines... } public: inline V* find(key) { return &_find(key); } std::cout << *find(a_key);
This would return a pointer to a temporary, which I didn't think about. The only thing that can be done similar to this is to do a lot of processing in the _find() and do the last step and the return of the pointer in find() to minimize the amount of inlined code.
private:
W* _find(key) {
... // a few dozen lines...
}
public:
inline V* find(key) {
return some_func(_find(key)); // last steps on W to get V*
}
std::cout << *find(a_key);
Or as yet another responder mentioned, we could return a reference to V in the original version (again, not sure why we're all blind to the trivial stuff at first glance... see discussion.)
private:
V& _find(key) {
... // a few dozen lines...
}
public:
inline V* find(key) {
return &_find(key);
}
std::cout << *find(a_key);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
_find
返回一个V
类型的临时对象。find
然后尝试获取临时地址并返回它。临时物品不会持续很长时间,因此得名。因此_find
返回的临时值在获取其地址后将被销毁。因此,find 将返回一个指向先前销毁的对象的指针,这是不好的。_find
returns a temporary object of typeV
.find
then attempts to take the address of the temporary and return it. Temporary objects don't last very long, hence the name. So the temporary returned by_find
will be destroyed after getting its address. And thereforefind
will return a pointer to a previously destroyed object, which is bad.我已经看到它的发展方向。这实际上取决于编译器和优化级别。即使它确实被内联,我也见过编译器不会优化它的情况。
查看它是否确实得到优化的唯一方法是实际查看反汇编。
您可能应该做的是制作一个手动内联它们的版本。然后对其进行基准测试,看看是否确实获得了显着的性能提升。如果不是,那么整个问题就没有意义了。
I've seen it go either way. It really depends on the compiler and the level optimization. Even when it does get inlined, I've seen cases where the compiler will not optimize this out.
The only way to see if it does get optimized out it is to actually look at the disassembly.
What you should probably do is to make a version where you manually inline them. Then benchmark it to see if you actually get a noticeable performance gain. If not, then this whole question is moot.
您的代码(即使是第二个版本)已损坏。
_find
返回一个V
,find
在返回其地址之前立即销毁它。如果
_find
返回一个V&
到一个超出调用寿命的对象(从而产生一个正确的程序),那么取消引用将是一个无操作,因为引用是无操作的与机器代码级别的指针不同。Your code (even in its second incarnation) is broken.
_find
returns aV
, whichfind
destroys immediately before returning its address.If
_find
returned aV&
to an object that outlives the call (thus producing a correct program), then the dereference would be a no-op, since a reference is no different to a pointer at the machine code level.