Jra*_*xon 11 c++ python vector
说我有以下代码
class Car {
public:
string color;
string name;
Car(string c, string n): color(c), name(n){}
}
int main() {
vector<Car> collection1;
vector<Car> collection2;
collection1.emplace_back("black", "Ford");
collection1.emplace_back("white", "BMW");
collection1.emplace_back("yellow", "Audi");
//Question comes here
collection2.push_back(collection1[0]);
}
Run Code Online (Sandbox Code Playgroud)
现在我相信这是一个深刻的副本collection1[0].我尝试过使用collection2.emplace_back(move(collection1[0])),但随后数据字段collection1[0]将消失.我只想让这个"黑色福特"存在于两个向量中,并且通过任一向量对这个特定对象所做的更改将反映在两个向量上.
我猜测对于真实对象的向量,此向量的元素占用实际内存.因此,元素collection1必须独立于任何元素collection2.我认为最简单的方法是让collection1和collection2成为指针的向量并指向相同的向量Car.但是有没有可能的方法使上面的代码工作,而不使用指针向量.我最终希望将这两个集合返回到前一个函数,因此制作指针向量是没有意义的.
简而言之,我想List.append()在python中模拟该方法.
collection1 = [Car("black", "Ford"),Car("white", "BMW"),Car("yellow", "Audi")]
collection2 = []
collection2.append(collection1[0])
collection2[0].color = "blue" // This affects collection1 as well
Run Code Online (Sandbox Code Playgroud)
Ser*_*sta 13
在C++语言中,标准集合实际上包含对象,而在其他语言(如Python或Java)中,它们实际上包含对存储在别处的对象的引用(或指针).但由于C++不包含垃圾收集,因此必须在其他地方明确管理对象的生命周期.
该设计的结果是,为了允许在两个不同的集合中使用相同的对象,您必须使用指针或引用的集合(注意,C++不直接允许引用集合;但是,std::ref为此创建).
根据您的使用情况,您可以使用原始指针(如果已经管理了实际对象的生命周期),或者使用std::shared_ptr内部管理引用计数的智能指针(此处),以确保在最后一个对象被自动销毁时shared_ptr被毁了.这与Python对对象的引用相差不远,前提是您知道对末尾的破坏shared_ptr实际上会破坏对象(*).换句话说,如果你不想让它变成悬空,不要保留任何其他指针或引用它.
或者,如果集合不是对称的 - 也就是说,如果一个集合实际上包含所有对象,而另一个集合只包含对前一个对象的引用 - 参考将是你最好的选择,第二个集合可能是一个std::vector<std::reference_wrapper<Car>>.
根据MvG评论添加.
Python对象和C++ shared_ptr之间可能存在令人讨厌的差异.Python有一个完整的垃圾收集器,它足够聪明,可以检测循环引用,并在没有外部引用时立即销毁循环.例:
>>> b = ['x']
>>> a = ['y']
>>> b.append(a)
>>> a.append(b)
>>> a
['y', ['x', [...]]]
>>> b
['x', ['y', [...]]]
Run Code Online (Sandbox Code Playgroud)
a包含一个ref到b,其中包含一个ref ...
如果a被删除(或超出范围),b仍将包含完整链
>>> del a
>>> b
['x', ['y', [...]]]
Run Code Online (Sandbox Code Playgroud)
但如果a和b都被删除(或超出范围),gc将检测到没有更多的外部引用并将破坏所有内容.
不幸的是,如果你设法建立一个C++对象的循环,std::shared_ptr因为它只使用本地引用计数,每个对象将有一个引用到另一个,它们将永远不会被删除,即使它们将超出范围,这将导致内存泄漏.一个例子:
struct Node {
int val;
std::shared_ptr<Node> next;
};
a = make_shared<Node>(); // ref count 1
b = make_shared<Node>();
a.next = std::shared_ptr<Node>(b);
b.next = std::shared_ptr<Node>(a); // ref count 2!
Run Code Online (Sandbox Code Playgroud)
地狱来了:即使a和b都超出范围,引用计数仍然是1,共享指针永远不会删除它们的对象,没有循环引用通常会发生什么.程序员必须明确地处理并打破循环(并禁止它发生).例如,b.next = make_shared<Node>();在b超出范围之前就足够了.
既然你提到你不喜欢指针,你可以使用引用,但是向量不能存储引用(因为它们不可复制和可赋值).但是std::reference_wrapper在可复制和可分配对象中包装引用.
std::reference_wrapper是一个类模板,它在可复制的可分配对象中包装引用.它经常被用作在标准容器(例如std::vector)中存储引用的机制,这些容器通常不能保存引用.来源:http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
vector<Car> collection1;
collection1.emplace_back("black", "Ford");
collection1.emplace_back("white", "BMW");
collection1.emplace_back("yellow", "Audi");
vector<std::reference_wrapper<Car>> collection2{collection1.begin(),
collection1.end()};
Run Code Online (Sandbox Code Playgroud)
使用这种方式,collection2指的是相同的对象collection1.例如:
collection1[0].name = "frogatto!";
std::cout << collection2[0].get().name;
// prints 'frogatto!'
Run Code Online (Sandbox Code Playgroud)
重要:
请注意,不建议使用这种方式,因为您必须拥有另一个管理插入和移除的实体,并对其执行collection1适当的操作collection2.@ Serge Ballesta的回答比我好.使用std::shared_ptr.尝试爱和拥抱指针:)