C++ 为什么std::set和set::map';的默认构造函数需要堆分配吗?

C++ 为什么std::set和set::map';的默认构造函数需要堆分配吗?,c++,memory-management,stdmap,stdset,C++,Memory Management,Stdmap,Stdset,当我尝试这个: #include <functional> #include <iostream> #include <memory> #include <set> template<class T> struct MyAlloc { typedef std::allocator<T> Base; typedef typename Base::value_type value_type; typed

当我尝试这个:

#include <functional>
#include <iostream>
#include <memory>
#include <set>

template<class T>
struct MyAlloc
{
    typedef std::allocator<T> Base;
    typedef typename Base::value_type value_type;
    typedef typename Base::pointer pointer;
    typedef typename Base::const_pointer const_pointer;
    typedef typename Base::reference reference;
    typedef typename Base::const_reference const_reference;
    typedef typename Base::size_type size_type;
    typedef typename Base::difference_type difference_type;
    Base a;
    MyAlloc() { }
    template<class U> MyAlloc(MyAlloc<U> const &) { }
    template<class U> struct rebind { typedef MyAlloc<U> other; };
    pointer allocate(size_type n, void const * = NULL)
    {
        std::cout << "Allocating " << n << " objects" << std::endl;
        return this->a.allocate(n);
    }
    void deallocate(pointer p, size_type n) { return this->a.deallocate(p, n); }
};

int main(int argc, char *argv[])
{
    std::set<int, std::less<int>, MyAlloc<int> > set;
}
#包括
#包括
#包括
#包括
模板
结构MyAlloc
{
typedef std::分配器基;
typedef typename Base::value_type value_type;
typedef typename Base::指针;
typedef typename Base::const_指针const_指针;
typedef typename Base::reference引用;
typedef typename Base::const_reference const_reference;
typedef typename Base::size\u type size\u type;
typedef typename Base::difference\u type difference\u type;
碱基a;
MyAlloc(){}
模板MyAlloc(MyAlloc常量&){}
模板结构重新绑定{typedef MyAlloc other;};
指针分配(大小\u类型n,void const*=NULL)
{

Std::Cu> < C++标准当然不要求内存分配给默认构造的对象。为什么一个实现可能会在默认代码的构造函数中分配给一个<代码>::MAP< /Cord>我不知道。一个原因是确保它不试图将一个潜在的大分配器嵌入到分配的OB栈中。您需要查看实现,以了解它为什么在堆上分配内存。

我想我自己也明白了。VisualC++似乎是正确的,Clang和GCC似乎是错误的。 这是因为
swap
不应使
std::set
std::map
的迭代器无效。如果我们尝试此代码:

#include <set>
#include <iostream>
int main()
{
    std::set<int> a, b;
    std::set<int>::iterator end = a.end();
    a.swap(b);
    b.insert(end, 1);
    std::cout << b.size() << std::endl;
    return 0;
}
#包括
#包括
int main()
{
标准:集合a,b;
std::set::iterator end=a.end();
a、 掉期(b);
b、 插入(末端,1);

std::你能用微软的VC++吗?@MaximYegorushkin:是的。问得好。我认为这不是“必要的”。我在我的机器上运行这个程序时,没有看到动态分配(带有叮当声的OSX)@H2CO3:有意思……如果没有必要的话,我觉得这会是一个非常明显的优化,Dinkumware会把它放进去。让我想知道为什么它不在那里,我觉得它可能会破坏一些代码,但我不确定它会是什么。我记得曾经有一个
静态
全局节点的技巧,它以某种方式标记为空或结束,而不是结束
nullptr
因此,在某些情况下,实现可能会避免额外的分支:如果是这样的话,也许这就是解决这个问题的方法(它有问题)但是,您可以引用一个标准的命令,即交换是否不使STD::SET或STD::MAP的迭代器无效?您会提交一个bug报告吗?或者我应该这样做吗?NITPY:Clang和GCC不是C++库I实现时,它们都可以使用libstdc++并且Clang更喜欢它自己的libc++。相比之下,MSVC只能使用它自己的分裂的纯粹软件实现。我说分裂是因为MSVC的库代码中存在大量的编译器错误解决方法。另外,你错了(见注2)。请参见我链接的答案,注1,c++03。此外,在手机上键入这些东西,虽然可能,但很难而且耗时;-)@rubenvb:很高兴看到这个问题被引用:)@rubenvb:哇,谢谢你的提示。我想解释可能是他们试图避免破坏依赖
end迭代器保持有效。谢谢!