假设我通过const引用将变量传递给函数,比如func2。经过一些测试,我想在调用它之前修改它的参数。这是一个解释我的目标的伪代码。
struct strA
{
int a;
VectorXd v;
};
strA func2(const int& a, const VectorXd& v){...};
strA func1(...){...};
int main(){
int a;
VectorXd v;
bool test;
if(test){
strA B;
// some amount of work is required to get the members of B
B = func1(...);
func2(B.a, B.v);
} else {
func2(a, v);
};
return 0;
}
这段代码工作正常但是为了可读性和通用性,我想知道是否存在更好的解决方案。这是另一种选择
strA func3(const int& a, const VectorXd& v, test)
{
strA B;
if(test){ // some amount of work is required to get the members of B
B = func1(...);
} else { // map the arguments to a structure
B.a = a; // the original arguments passed by constant reference
B.v = v;
};
return B;
};
int main(){
int a;
VectorXd v;
bool test;
strA B;
B = func3(a,v,test);
func2(B.a, B.v);
return 0;
}
在test==true
(显然)没有问题保持结构B和参数a和v作为那些实体的情况下。但是,当test==false
替代只是在结构B中复制原始参数a和v(在我的应用程序中是几个大向量)。是否有更清洁的方法或我应该坚持第一个?顺便说一下,由于这段代码出现在循环中,我很烦恼,所以我更喜欢避免在几个地方复制相同的代码。
谢谢!
答案 0 :(得分:0)
我建议采用两种方法:
首先:让我们在strA
内的堆上创建类func3
的对象,并返回指向该对象的指针(例如strA* func3(..)
而不是copy { {1}}):
strA func3(..)
然后以下列方式使用:
strA* func3(..) {
strA* B = new strA;
... // change B.someMember to B->someMember everywhere
return B;
}
警告:您必须自己管理对象的生命周期,在使用后显式释放内存(调用strA* B;
...
B = func3(..);
...
delete B;
)。但是,请查看std::unique_ptr
和其他一些智能指针(如果您可以使用delete
)。
第二:将对象的引用传递给函数,在那里修改并返回c++11
:
void
并使用:
void func3(/*previous arguments*/, strA* pobj) {
// nothing to allocate
... // change B.someMember to pobj->someMember everywhere
// nothing to return as we've modified an object
}
注意:但是您的strA B;
...
func3(..., &B);
仍会返回副本,因此您可以将其修改为原样或保持原样。
答案 1 :(得分:0)
您提供的两个选项具有相同的副本数量。 阅读完您的评论后,我就可以收集到这些内容:
让我们看一下这句话:
strA B;
该行初始化名为strA
的{{1}}类型的本地变量。
现在让我们来看看这句话:
B
现在,此行从strA B = foo(3, 4);
返回的临时对象的副本初始化名为strA
的{{1}}类型的本地变量。
的编译器进行了特殊优化
所以,第二行可能不太理想,但......不是真的。在第一行中,对象未使用正确的数据进行初始化,它使用默认构造函数。所以你在解决方案中做的事情如下:
B
foo
strA B;
B = foo(3,4);
foo
醇>
此说明根据优化情况再次变化。此外,如果您使用的是c ++ 11,由于
,它会变得更复杂B
这两个世界都受到影响,不仅可能调用operator=
,它还使用默认构造函数。但是代码的可读性较差,使编译器难以优化。
我不确定您要阻止哪个副本。但我的建议是这个 -
您可能认为您的代码会很慢,但您无法真正了解这一点。编译器几乎可以实现"黑暗魔法"尝试将代码优化到最高级别(确保在gcc上运行Move Semantics
标志)
部分代码
由于我还不确定你要修复的是什么,我只是给你一些可能(也可能没有)帮助的指针。但首先是代码:
operator=
始终初始化并避免-O3
。如果我告诉您始终使用void calc_and_call(const int& a, const VectorXd& v)
{
const strA B = func1(a, b);
func2(b.A, b.B);
}
void func2_wrapper(const int& a, const VectorXd& v, test)
{
if(test)
calc_and_call(a, v);
else
func2(a, v);
};
保持对象的范围尽可能小(这里是两行)