C++ 按值传递,使用std::vector赋值时没有深度复制?
理解C++ 按值传递,使用std::vector赋值时没有深度复制?,c++,vector,set,C++,Vector,Set,理解std::set.insert和std::vector行为。 请考虑以下情况: A.h class A { uint id; vector<double> values; operator<(const A& argA) const; } A类{ 单元id; 向量值; operatorid=argId; 此->值=argValues; } A::运算符值[0]
std::set.insert
和std::vector
行为。
请考虑以下情况:
A.h
class A {
uint id;
vector<double> values;
operator<(const A& argA) const;
}
A类{
单元id;
向量值;
operatorid=argId;
此->值=argValues;
}
A::运算符值[0]
B.cpp
A::A(uint argId, vector<double> argValues) {
this->id = argId;
this->values = argValues;
}
A::operator<(const A& argA) const {
// it's guaranteed that there's always at least one element in the vector
return this->values[0] < argA.values[0];
}
std::set<A> mySet;
for (uint i = 0; i < (uint) 10; i++)
{
vector<double> tempVector(3);
for (uint j = 0; j < (uint) 3; j++) {
tempVector[j] = j;
}
myset.insert(A(i + 1, tempVector));
}
std::set mySet;
对于(uint i=0;i<(uint)10;i++)
{
向量tempVector(3);
对于(uint j=0;j<(uint)3;j++){
tempVector[j]=j;
}
myset.insert(A(i+1,tempVector));
}
据我所知,tempElement
拥有一个深度复制的向量(值),因为向量在其构造函数中按值传递并赋值。因此,循环我不应该破坏我的集合中添加的元素。但是插入*tempElement
会中断-SIGSEV。按照我的逻辑,这应该行得通。。。感谢您的帮助
编辑:代码在插入过程中崩溃(第二个元素);set调用LT运算符,尝试访问传递参数的向量,但无法访问。在创建传递id和向量的位置之前,我检查传递的向量是否包含正确的元素 对于一个小的向量,这应该无关紧要,但是如果你有一个大的数组,并且继续复制它会很昂贵,那么你的a
应该包含一些浅层复制的指针。有几种选择:
boost::共享_阵列
boost::共享\u ptr
boost::shared_ptr
但在构造时传入了数组deleter
创建一个不可复制的,并具有一组指向的(共享)指针,其中包含一些比较函子,用于比较指针中的内容,而不是指针本身
请注意,使用shared_array
或shared_ptr
无法提取大小(元素数),因此必须单独存储。我认为这段代码中没有问题。但是我注意到您有一个向量tempVector,但是您将值分配给tempComponents。我看不到tempComponents声明,但我猜它的大小不同。不,没有理由在这里插入myset导致崩溃。问题一定在别处。如果您不使用默认的,那么可能在A的复制ctor中
但是,您的代码正在泄漏内存。当您插入到集合中时,*tempElement
将被复制到集合中,然后您分配给new
的原始元素将不再使用,但不会被删除。相反,您可以只做一个tempElement(i+1,tempVector)代码>以便在将对象复制到集合中后,它会被正确地销毁。或者,在这种情况下,您可以将其构造为直接传递给insert的临时文件:myset.insert(a(i+1,tempVector))
,在这种情况下,对象将被移动而不是复制,从而减少开销。或者您可以在适当的位置构造对象以避免移动:myset.emplace(i+1,tempVector)代码>
我还假设bytempComponents[j]=j
你的意思是tempVector[j]=j
。您可以将该循环替换为std::iota(begin(tempVector)、end(tempVector)、0)
编辑:或者您可以使用新的初始值设定项语法此外,由于每次向量都是相同的,因此您可以在循环外仅使用一个:
vector<double> tempVector(3) = {0.0,1.0,2.0}
std::set<A> mySet;
for (uint i = 0; i < (uint) 10; i++)
{
myset.emplace(i+1,tempVector);
}
使用大量更改的代码—但我看不出您所描述的问题
#include <set>
#include <vector>
using namespace std;
typedef unsigned int uint;
class A {
public:
A(uint argId, vector<double> argValues)
{
this->id = argId;
this->values = argValues;
}
bool operator < ( A const& a ) const
{
return a.id < id;
}
uint id;
vector<double> values;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::set<A> mySet;
for (uint i = 0; i < (uint) 10; i++)
{
vector<double> tempVector(3);
for (uint j = 0; j < (uint) 3; j++) {
tempVector[j] = j;
}
std::unique_ptr<A> tempElement(new A(i + 1, tempVector));
mySet.insert(*tempElement);
}
return 0;
}
#包括
#包括
使用名称空间std;
typedef无符号整数单元;
甲级{
公众:
A(uint argId,向量argvalue)
{
这个->id=argId;
此->值=argValues;
}
布尔运算符<(A常量和A)常量
{
返回a.id
为什么要动态分配tempElement?代码的编写方式存在内存泄漏(tempElement不会被删除)。您可以像这样在一行中完成所有操作:myset.insert(A(i+1,tempVector));当我删除myset时,它会被删除。它调用所有包含元素的析构函数。@Eric:不,它没有。放入集合的对象是动态分配的对象的副本。动态分配的对象本身已丢失。您没有向我们显示您的真实代码。请发布一个小的可编译示例(并且看起来不需要多个文件)。如前所述,class A
不能与std::set
一起使用,因为A
对象没有比较功能(也就是说,从C++11开始,没有操作符std::shared_ptr
。@WTP C++11还支持移动语义,如果代码重写正确的话)应该删除所有多余的副本。tempComponents
已从问题中删除。显然是一个副本粘贴错误。谢谢@bames54,但我使用的是不支持此语法的旧版本。@Eric您仍然可以执行插入(a(I+1,tempVector)
如果emplace
不受支持,您至少可以在不进一步更改代码的情况下尽快获得移动语义的好处。我将为C++03编译器添加一个示例代码版本。感谢您的努力,@Zac。我使用的另一个版本不支持std::unique\ptr语法。
#include <set>
#include <vector>
using namespace std;
typedef unsigned int uint;
class A {
public:
A(uint argId, vector<double> argValues)
{
this->id = argId;
this->values = argValues;
}
bool operator < ( A const& a ) const
{
return a.id < id;
}
uint id;
vector<double> values;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::set<A> mySet;
for (uint i = 0; i < (uint) 10; i++)
{
vector<double> tempVector(3);
for (uint j = 0; j < (uint) 3; j++) {
tempVector[j] = j;
}
std::unique_ptr<A> tempElement(new A(i + 1, tempVector));
mySet.insert(*tempElement);
}
return 0;
}