Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在没有默认(空)构造函数的情况下,如何允许模板化向量允许类型?_C++_Templates_Vector_Constructor - Fatal编程技术网

C++ 在没有默认(空)构造函数的情况下,如何允许模板化向量允许类型?

C++ 在没有默认(空)构造函数的情况下,如何允许模板化向量允许类型?,c++,templates,vector,constructor,C++,Templates,Vector,Constructor,我正在创建一个模板化的Vector类,但是,当将它的用法与std::Vector等比较时,我注意到它不允许没有默认(emtpty)构造函数的structs\classes。我将得到的错误是 error C2512: 'SomeStruct' : no appropriate default constructor available : while compiling class template member function 'Vector<Type>::Vector(voi

我正在创建一个模板化的Vector类,但是,当将它的用法与std::Vector等比较时,我注意到它不允许没有默认(emtpty)构造函数的structs\classes。我将得到的错误是

error C2512: 'SomeStruct' : no appropriate default constructor available
  : while compiling class template member function 'Vector<Type>::Vector(void)'
  : see reference to class template instantiation 'Vector<Type>' being compiled
错误C2512:“SomeStruct”:没有合适的默认构造函数可用
:编译类模板成员函数“Vector::Vector(void)”时
:请参阅正在编译的类模板实例化“Vector”的参考
然而,如果我去使用std::vector,这是允许的。这是我的测试用例

struct SomeStruct
{
    SomeStruct(int a){}
};
template<typename Type>
class Vector
{
public:
    Vector();

protected:
    Type* m_Data;
    unsigned int m_Count;
    unsigned int m_Capacity;
};
template<typename Type>
Vector<Type>::Vector()
{
    m_Capacity = 0;
    m_Count = 0;
    m_Data = new Type[m_Capacity];
}

void main()
{
    Vector<SomeStruct> test1;
}
struct SomeStruct
{
SomeStruct(inta){}
};
模板
类向量
{
公众:
向量();
受保护的:
类型*m_数据;
无符号整数m_计数;
无符号整数m_容量;
};
模板
向量::向量()
{
m_容量=0;
m_计数=0;
m_数据=新型[m_容量];
}
void main()
{
向量test1;
}
在没有默认(空)构造函数的情况下,如何允许模板化向量允许类型


(我知道我可以只使用std::vector,但我这样做是为了学习更多关于该语言的知识,并遇到类似的情况)

将此内容放入您的代码中:

SomeStruct() = default;
这将创建默认构造函数

或者这个:

SomeStruct() {}

同样的事情。

将此内容放入您的代码中:

SomeStruct() = default;
这将创建默认构造函数

或者这个:

SomeStruct() {}

同样的事情。

如果删除
m_数据=新类型[m_容量],并将此创建延迟到以后,它将工作。然而,正如已经指出的,
std::vector
具有相同的规则:如果您有
std::vector test1(10)您将得到相同的错误


另外,
void main()
也不好。如果删除
m_Data=new Type[m_Capacity],则它应始终至少为
int main

,并将此创建延迟到以后,它将工作。然而,正如已经指出的,
std::vector
具有相同的规则:如果您有
std::vector test1(10)您将得到相同的错误


另外,
void main()
也不好。它至少应该是
int main

对于没有默认构造函数的类型,这不起作用的原因是因为这一行:

    m_Data = new Type[m_Capacity]; 
上面这一行基本上做了两件事:分配足够的内存来容纳
m_Capacity
类型的
实例,然后构造每个
类型
,以便它们可以随时使用。由于无法通过此
new[]
语法实际提供任何构造函数参数,因此使用此语法时需要默认构造函数

std::vector
(以及其他标准容器)处理这个问题的方法是将内存分配过程和构造过程分离。也就是说,
std::vector
通过请求内存中没有“内容”的大块内存来分摊内存分配的成本。然后
std::vector
用于直接在该内存中构造对象

所以像这样的事情可能发生在一个
std::vector

// HUGE SIMPLICATION OF WHAT HAPPENS!!!
// EXPOSITION ONLY!!!
// NOT TO BE USED IN ANY PRODUCTION CODE WHATSOEVER!!!
// (I haven't even considered exception safety, etc.)

template<typename T>
class Vector
{
private:
    T* allocate_memory(std::size_t numItems)
    {
        // Allocates memory without doing any construction
        return static_cast<T*>(::operator new(sizeof(T)*numItems));
    }

    void deallocate_memory()
    {
        ::operator delete(buffer);
    }
    // ...

public:
    void push_back(const T& obj)
    {
        if(theresNotEnoughRoom()) {
            std::size_t newCapacity = calculateNewCapacity();
            T* temp = allocate_memory(newCapacity);
            copyItemsToNewBuffer(temp);
            deallocate_memory(buffer);
            buffer = temp;
            bufferEnd = temp+newCapacity;
        }
        new (bufferEnd) T(obj); // Construct a new instance of T at end of buffer.
        ++bufferEnd;
    }

    void pop_back()
    {
        if(size() > 0) {
            --bufferEnd;
            bufferEnd->~T();
        }
    }

    // ...

private:
    T* buffer;
    T* bufferEnd;
    // ...
};
//将发生的事情大大简化了!!!
//只有博览会!!!
//不用于任何生产代码中!!!
//(我甚至没有考虑过异常安全等)
模板
类向量
{
私人:
T*分配内存(标准::大小\u T numItems)
{
//分配内存而不进行任何构造
返回静态_cast(::运算符new(sizeof(T)*numItems));
}
void deallocate_内存()
{
::运算符删除(缓冲区);
}
// ...
公众:
无效推回(常量T和obj)
{
如果(没有足够的房间()){
std::size\u t newCapacity=calculateNewCapacity();
T*temp=分配内存(新容量);
copyItemsToNewBuffer(温度);
释放内存(缓冲区);
缓冲区=温度;
bufferEnd=温度+新容量;
}
new(bufferEnd)T(obj);//在缓冲区的末尾构造一个新的T实例。
++缓冲端;
}
void pop_back()
{
如果(大小()>0){
--缓冲端;
bufferEnd->~T();
}
}
// ...
私人:
T*缓冲器;
T*bufferEnd;
// ...
};
所以这里发生的事情是,我们假设的
Vector
类分配了一块相对较大的内存,然后当项目被推送或插入时,该类会在内存中放置新的内容。因此,这消除了默认构造函数要求,因为除非调用方请求,否则我们实际上不会构造任何对象

正如您已经看到的,一个
std::vector
类需要做大量的簿记工作,以使它所做的工作高效、安全。这就是为什么我们敦促人们使用标准容器,而不是推出自己的容器,除非你真的知道自己在做什么。创建一个高效、安全和有用的向量类是一项巨大的任务


要了解其中涉及的内容,请看一篇Bjarne Stroustrup撰写的论文,其中讨论了“简单向量”实现(第3.1节)。您将看到,实现它并不是一件小事。

这对于没有默认构造函数的类型不起作用的原因是因为这一行:

    m_Data = new Type[m_Capacity]; 
上面这一行基本上做了两件事:分配足够的内存来容纳
m_Capacity
类型的
实例,然后构造每个
类型
,以便它们可以随时使用。由于无法通过此
new[]
语法实际提供任何构造函数参数,因此使用此语法时需要默认构造函数

std::vector
(以及其他标准容器)处理这个问题的方法是将内存分配过程和构造过程分离。也就是说,
std::vector
通过请求内存中没有“内容”的大块内存来分摊内存分配的成本。然后
std::vector
用于构造
m_Data = new Type[m_Capacity];
int typeSize = sizeof(Type);
char* buffer = new char[typeSize * 2];
Type* typeA = new(buffer) Type(default_value);
Type* typeB = new(&buffer[typeSize]) Type(default_value);