【问题标题】:Does set::insert saves a copy or a pointer C++set::insert 是否保存副本或指针 C++
【发布时间】:2011-02-25 21:35:22
【问题描述】:

函数set::insert 是否保存指向元素的指针或它的副本。意思是,我可以做下面的代码,还是我必须确保指针没有被删除?

int *a;
*a=new int(1);
set<int> _set;
_set.insert (*a);
delete a;
*a=new int(2);
_set.insert (*a);
delete a;

我用int 给出了示例,但我的实际程序使用的是我创建的类。

【问题讨论】:

    标签: c++ set stdset


    【解决方案1】:

    所有 STL 容器都存储插入数据的副本。在第三段的“描述”部分查看here:一个容器(和std::set 模拟一个容器)拥有它的元素。有关更多详细信息,请查看以下脚注 [1]。特别是对于std::set,请在“类型要求”部分下查看hereKey 必须是可分配的。

    除此之外,您还可以轻松测试:

    struct tester {
      tester(int value) : value(value) { }
      tester(const tester& t) : value(t.value) {
        std::cout << "Copy construction!" << std::endl;
      }
      int value;
    };
    
    // In order to use tester with a set:
    bool operator < (const tester& t, const tester& t2) {
      return t.value < t2.value;
    }
    
    int main() {
        tester t(2);
    
        std::vector<tester> v;
        v.push_back(t);
    
        std::set<tester> s;
        s.insert(t);
    }
    

    你总是会看到Copy construction!

    如果你真的想存储对象的引用之类的东西,你可以存储指向这些对象的指针:

    tester* t = new tester(10);
    {
        std::set<tester*> s;
        s.insert(t);
        // do something awesome with s
    } // here s goes out of scope just as well the contained objects
      // i.e. the *pointers* to tester objects. The referenced objects
      // still exist and thus we must delete them at the end of the day:
    delete t;
    

    但在这种情况下,您必须注意正确删除对象,这有时非常困难。例如,异常会极大地改变执行路径,而您永远无法到达正确的delete

    或者你可以使用像boost::shared_ptr这样的智能指针:

    {
        std::set< boost::shared_ptr<tester> > s;
        s.insert(boost::shared_ptr<tester>(new tester(20)));
        // do something awesome with your set
    } // here s goes out of scope and destructs all its contents,
      // i.e. the smart_ptr<tester> objects. But this doesn't mean
      // the referenced objects will be deleted.
    

    现在智能指针会照顾您并在正确的时间删除它们引用的对象。如果您复制了其中一个插入的智能指针并将其转移到其他地方,则在最后一个引用该对象的智能指针超出范围之前,通常引用的对象不会被删除。

    哦,顺便说一句:从不std::auto_ptrs 用作标准容器中的元素。它们奇怪的复制语义与容器存储和管理数据的方式以及标准算法如何操作它们的方式不兼容。我敢肯定 StackOverflow 上有很多关于这个不稳定问题的问题。

    【讨论】:

    • 综合解答!或许,值得一提的是 Boost Pointer Container。 boost::ptr_set&lt; tester &gt; s;s.insert( new tester(20) );
    【解决方案2】:

    std::set 将复制您插入的元素。

    【讨论】:

    • 我在标准中找不到支持这一点的参考。有插入的签名和表 69,但这些都没有说明std::set 有义务复制元素。我确定std::set 必须 复制元素以确保正确性,但我还没有找到支持它的参考。 :-S
    • 也就是说,您没有发布“真实”代码,所以我不知道它是否类似,但如果您不需要,请不要使用免费商店。工作量大,成本高(是的,免费商店不是免费的),而且存在陷阱。
    【解决方案3】:

    您正在将指针保存到集合中。

    指针指向的对象没有被复制。
    因此调用 delete 后,集合中的指针无效。

    注意:您可能只想保存整数。

    int a(1);
    set<int>  s;
    s.insert(a); // pushes 1 into the set
    s.insert(2); // pushes 2 into the set.
    

    其他几点说明:

    • 注意标识符名称开头的下划线。
    • 使用智能指针来保存指针。

    指针:

     std::auto_ptr<int>  a(new int(1));
     set<int*>           s;
     s.insert(a.release());
    
     // Note. Set now holds a RAW pointer that you should delete before the set goes away.
     //       Or convert into a boost::ptr_set<int> so it takes ownership of the pointer.
    

    【讨论】:

    • 作为一个额外的说明,不要将auto_ptr's 放入 STL 容器中:) (如示例所示,放入容器时调用 release)
    • 正在保存整数。他在插入时取消引用指针。尽管关于指针,你是正确的,并且考虑到他对他的new 电话的困惑,这可能是他实际上试图问的问题。
    • auto_ptr 在这里有什么帮助?
    • 我不喜欢 RAW 指针。如果创建 s 失败(由于某些异常),我的 a 对象将被正确删除。
    • 原则上同意原始指针。虽然,如果你在堆栈上创建一个简单的集合失败,你可能有比 4 字节内存泄漏更大的鱼要炸。
    【解决方案4】:
    int *a;     
    *a=new int(1);
    

    此代码错误,因为您尝试使用存储在地址a 的值,这是一个垃圾。

    并且,每个 stl 都包含 copy 元素,除非您使用 move 语义,其中 insert() 和 push_back() 在 C++0x 中采用右值引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-07
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多