C++ 通过引用将堆栈分配的值传递给C++;
我正在使用一个外部库,有一些代码让我暂停。基本上,有一个向量是在循环中分配的(在堆栈上)。然后,该向量通过引用传递给某个对象的构造函数,并用于初始化该对象的一个未声明为引用的向量字段。新创建的对象是否包含对不再存在的对象的引用?或者这只是复制向量的一种更有效的方法,在这种情况下,在堆栈上分配向量并没有什么区别 下面是一个简单的例子:C++ 通过引用将堆栈分配的值传递给C++;,c++,reference,initialization,C++,Reference,Initialization,我正在使用一个外部库,有一些代码让我暂停。基本上,有一个向量是在循环中分配的(在堆栈上)。然后,该向量通过引用传递给某个对象的构造函数,并用于初始化该对象的一个未声明为引用的向量字段。新创建的对象是否包含对不再存在的对象的引用?或者这只是复制向量的一种更有效的方法,在这种情况下,在堆栈上分配向量并没有什么区别 下面是一个简单的例子: class Holder { public: Holder(vector<int>& vref) : vec(vref) {}
class Holder {
public:
Holder(vector<int>& vref) : vec(vref) {}
vector<int> vec;
}
Holder* MakeHolder() {
vector<int> v {1, 2};
return new Holder(v);
}
int main() {
Holder *h = MakeHolder();
}
类持有者{
公众:
持有者(矢量和vref):矢量(vref){}
向量向量机;
}
持有者*MakeHolder(){
向量v{1,2};
返还新持有人(五);
}
int main(){
Holder*h=MakeHolder();
}
它的成员变量是向量,而不是引用,因此它是持有者自己的副本(每个std::vector
都拥有自己的元素)
新创建的对象是否包含对不再存在的对象的引用
否。Holder
按值存储向量,因此它的向量和函数本地向量是不同的对象
或者这只是复制向量的一种更有效的方法,在这种情况下,在堆栈上分配向量并没有什么区别
对。如果
Holder(vector<int>& vref) : vec(vref) {}
它允许您接受左值和右值
新创建的对象是否包含对不再存在的对象的引用
否,为初始化成员变量vec
或者这只是复制向量的一种更有效的方法,在这种情况下,在堆栈上分配向量并没有什么区别
是的,但通常的做法是使用const
引用以避免在按值传递参数时复制ctor:
Holder(cont vector<int>& vref) : vec(vref) {}
Holder(contvector&vref):vec(vref){
因此,可能有人犯了一个错误,错过了const
,或者有其他原因不在这里使用const引用
注意:使用移动语义,在某些情况下,通过(const)引用传递对象的效率甚至低于通过值传递对象的效率。没有对已离开对象的引用,但我肯定不会称之为“有效”。如果ctor初始化器中没有std::move
,则必须复制向量
你可以把std::move
放在那里,但是Holder
使用起来会有点混乱
就我个人而言,我会通过值将向量引入,这样调用范围就可以std::move
进入它(或者传递一个临时变量,它将自动执行此操作),然后std::move
构造函数参数进入新成员。这样的话,你整个时间都只有一个向量
class Holder {
public:
Holder(vector<int> vref) : vec(std::move(vref)) {}
vector<int> vec;
}
Holder* MakeHolder() {
vector<int> v {1, 2};
return new Holder(std::move(v)); // Or just `return new Holder({1,2});`
}
int main() {
Holder *h = MakeHolder();
}
(有些人会拼写MakeHolder()
的返回类型auto
,但我不会。我认为知道你将得到什么是很重要的。例如,否则你必须阅读代码才能知道结果的所有权语义!它是原始指针吗?其他什么?)我认为为示例提供内存不是一个好主意leak@Slava我只更改了相关的元素,其余的是OP的代码。但你可能是对的,指出这一点是个好主意。将添加。感谢您的回复。我不清楚我的示例为什么会出现内存泄漏。除非你的意思是当main()结束时内存泄漏?还有,难道不需要在某个时候复制吗?或者(在您建议的代码中,始终只有一个向量)MakeHolder方法的Holder对象和堆栈帧只是引用同一个向量,直到方法完成为止?@EricAtAIR:是的,这就是我的意思-可能您的“真实”代码没有该缺陷,但无论如何,智能指针将有助于降低风险。没有必要复制:这就是移动语义的美。原始的v
被“移出”-其数据和状态被支架内的新版本窃取。这是不明显的,因为现在半死不活的v
会立即超出范围,因为MakeHolder()
会返回。一本C++11(或更新版本)的书在这里会很有用。
Holder(cont vector<int>& vref) : vec(vref) {}
class Holder {
public:
Holder(vector<int> vref) : vec(std::move(vref)) {}
vector<int> vec;
}
Holder* MakeHolder() {
vector<int> v {1, 2};
return new Holder(std::move(v)); // Or just `return new Holder({1,2});`
}
int main() {
Holder *h = MakeHolder();
}
class Holder {
public:
Holder(vector<int> vref) : vec(std::move(vref)) {}
vector<int> vec;
}
std::unique_ptr<Holder> MakeHolder() {
return std::make_unique<Holder>({1,2});
}
int main() {
auto h = MakeHolder();
}