是否可以将C ++(或C ++ 0x)中局部变量的所有权转移给函数,在返回后将其保留为未定义,以便进行优化?
struct A {
int a[100000];
};
int func(A& s){
//s should now be "owned" by func and be undefined in the calling function
s.a[2] += 4;
return s.a[2];
}
int main(){
A s;
printf("%d\n", func(s));
//s is now undefined
}
我希望优化函数“func”以简单地返回s.a [2] +4,但不改变内存中的实际值,就像“s”是“func”中的局部变量一样。 如果不能在标准C ++中完成,是否可以在g ++中进行一些扩展?
答案 0 :(得分:5)
不,这不可能,无论是标准还是通过扩展,那是因为没有优化值。编译器可以简单地证明在这种情况下不再有对局部变量的引用。如果不做其他事情,你可以通过
来模仿这种效果int main() {
{
A s;
printf("%d\n", func(s));
}
}
能够做那种事情会非常危险,没有任何好处。
答案 1 :(得分:2)
将优化留给编译器 - 在简单的情况下,它可能会这样做。
不要忘记 - 过早的优化是万恶之源。
答案 2 :(得分:1)
我希望合理的优化编译器能够在没有任何特殊提示的情况下进行这样的优化,如果在函数返回后确实没有引用局部变量s,假设变量和函数在同一个编译单元或您启用了某种形式的链接时间代码生成。
您可以通过确定局部变量的范围来帮助优化器,使其明确表示在函数调用之后无法访问优化器:
int main() {
{
A s;
printf("%d\n", func(s));
} //s is now undefined
}
如果您的某个特定案例似乎没有像您认为的那样有效地进行优化,那么您可以提供有关您情况的更多详细信息。在这种情况下,我有点不清楚函数'拥有'局部变量到底是什么意思,因为你确实想在函数返回后访问它。
答案 3 :(得分:1)
您正在混合不同的问题,如所有权,堆栈展开和值参数。
是否可以转移本地变量的所有权
没有。局部变量是定义范围的本地变量,其他任何人都无法看到它们或以任何方式操纵它们。您可以向函数传递局部变量的值,对局部变量的引用或局部变量的地址。当传递引用或指向局部变量的指针时,calee可以操纵变量的内容,但不是无论如何都可以影响调用者帧中变量的范围。最常见的“所有权”转移意味着按值传输指针并依赖被调用者获取分配的内存的所有权。所有形式的变量传递(通过值,通过ref,通过指针)都可以处理这个问题,内存分配所有权的问题是不同的。
我希望优化函数“func”以简单地返回s.a [2] +4, 但不能改变内存中的实际值,
然后这样做,为什么要让它变得更复杂?
int func(const A& s){
return s.a[2] + 4;
}
这将完全按照您的描述进行,但这不太可能是您实际要求的。实现信仰的飞跃并调用一些心灵力量,你会猜到你真正要求的是一个对象是否同时在被调用者范围内改变并且在调用者范围内完好无损?答案显然是否定的,因为根据调用者的不同,内存不能有不同的值。您可以传递对象的副本(按值传递),这将允许调用者在其认为合适时操纵其自己的对象副本,而不影响调用者作用域中的原始副本。或者你可以传递const引用,防止被调用者修改它,并让被调用者复制出需要修改的内容。
答案 4 :(得分:1)
我很惊讶没有其他人发布这个,但听起来最接近你想要的只是删除引用,并将函数调用放在一个单独的范围
int func(A s){ //removed the &
//s is "owned" by func and changes don't touch anyone else's A objects
s.a[2] += 4;
return s.a[2];
}
int main(){
{
A s;
printf("%d\n", func(s));
// s hasn't changed, func had it's own copy.
} // s goes out of scope and is deleted
//s is now undefined
}
答案 5 :(得分:0)
如果您愿意,也可以使用指针。下面的代码示例更改了您的func(A)以获取对指针的引用,以便在重新分配后可以将其安全地转为null。
它有点诡异,但如果您绝对需要,它是可能的。然而,可以避免过早的优化。
int func(A*& s) {
int retVal = s->a[2] + 4;
delete s;
s = NULL;
return retVal;
}
int main() {
A* s = new A();
printf("%d\n", func(s));
}
答案 6 :(得分:0)
您可以使用旧的C ++ 03 auto_ptr。调用函数留有一个指向nullptr的auto_ptr,而函数接管并删除了s。
int func(std::auto_ptr<A> s){
//s is "owned" by func and be undefined in the calling function
s.a[2] += 4;
return s.a[2];
}
int main(){
std::auto_ptr<A> s = new A();
printf("%d\n", func(s)); //destructive copy of pointer
//s is now nullptr
}