以下代码运行良好,但据我所知,它不应该
#include <iostream>
#include <vector>
struct Data
{
explicit Data():value(1){}
int value;
};
struct Foo
{
explicit Foo(Data& data):data_(data){}
inline void print() const
{
std::cout<<data_.value<<std::endl;
}
Data& data_;
};
void addEntry(std::vector<Foo>& vec)
{
Data data;
Foo foo(data);
vec.push_back(foo);
}
int main()
{
std::vector<Foo> vec;
addEntry(vec);
vec[0].print();
}
函数addEnty
创建一个名为Data
的{{1}}实例。然后创建一个名为data
的{{1}}实例,该实例存储对Foo
的引用。然后将该istance复制到向量foo
内。因此,当函数结束时,data
应包含悬空引用,因为vec
被销毁。我对吗?所以我希望获得一些调用方法vec[0]
的垃圾。是偶然的,我获得了正确的价值1还是我错过了什么?
为了使其正确,我会移动数据以避免悬空参考。所以我会用
修改构造函数data
和
的功能print()
通过这种方式,explicit Foo(Data&& data):data_(data){}
及其Foo foo(std::move(data));
内的副本包含实例foo
,而不是对它的引用。我对吗?这是正确的解决方案吗?这样,vec[0]
必须是data
类型或Foo::data_
类型?
答案 0 :(得分:2)
如您所知,由于悬空参考,您的示例代码具有未定义的行为。你看到的行为只是偶然。
一个采用左值参考的函数表示&#34;我将从你传入的任何内容中窃取数据&#34;。让构造函数接受这样的引用是好的,只要这些是你的语义,但它似乎不是你的例子的情况。
有可能采用参数by-value,然后将其移入成员变量:
struct Foo
{
explicit Foo(Data data):data_(std::move(data)){}
Data data_;
};
这样,客户端代码可以传递左值(1个副本,1个移动)或右值(2个移动)。只维护一个构造函数很方便,但如果Data
移动成本很高,这可能效率低下。
其他可能性是让一个构造函数采用转发引用,或者为rvalues维护一个重载,为lvalues维护一个重载。
答案 1 :(得分:2)
是的Foo将持有一个悬空参考。 Foo类应该保存Data not Data&amp;或数据&amp;&amp;。
#include <iostream>
#include <vector>
struct Data
{
explicit Data():value(1){}
int value;
};
struct Foo
{
// this is needed if you want to pass lvalue
Foo(const Data& data):data_(data)
{}
// for rvalue
Foo(Data&& data):data_(std::move(data))
{}
void print() const
{
std::cout<<data_.value<<std::endl;
}
Data data_;
};
void addEntry(std::vector<Foo>& vec)
{
vec.emplace_back(Foo(Data()));
// or
Data data;
// do somth with data
vec.emplace_back(Foo(std::move(data)));
// or
Data data;
// do somth with data
Foo foo {std::move(data)};
// do somth with foo, but
// do not use data here!!!
vec.push_back(std::move(foo));
}
int main()
{
std::vector<Foo> vec;
addEntry(vec);
vec[0].print();
}
答案 2 :(得分:1)
你是对的,这是偶然的,这实际上属于未定义的行为
字段应Data
键入Foo
以避免悬空参考
你可以用这种方式重写:
#include <iostream>
#include <vector>
struct Data
{
explicit Data():value(1){}
int value;
};
struct Foo
{
explicit Foo(Data&& data):data_(std::move(data)){}
inline void print() const
{
std::cout<<data_.value<<std::endl;
}
Data data_;
};
void addEntry(std::vector<Foo>& vec)
{
vec.emplace_back(Foo(Data()));
}
int main()
{
std::vector<Foo> vec;
addEntry(vec);
vec[0].print();
}