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();
}