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)

    我还假设by
    tempComponents[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;
    }