C++ C++;禁止自动初始化和销毁

C++ C++;禁止自动初始化和销毁,c++,initialization,destructor,C++,Initialization,Destructor,如何抑制类型的自动初始化和销毁?虽然T buffer[100]自动初始化buffer的所有元素,并在它们超出范围时将其销毁,但这不是我想要的行为 #include <iostream> static int created = 0, destroyed = 0; struct S { S() { ++created; } ~S() { ++destroyed; } }; t

如何抑制类型的自动初始化和销毁?虽然
T buffer[100]
自动初始化
buffer
的所有元素,并在它们超出范围时将其销毁,但这不是我想要的行为

#include <iostream>

static int created   = 0,
           destroyed = 0;

struct S
{
    S()
    {
        ++created;
    }
    ~S()
    {
        ++destroyed;
    }
};

template <typename T, size_t KCount>
class fixed_vector
{
private:
    T m_buffer[KCount];
public:
    fixed_vector()
    {
        // some way to suppress the automatic initialization of m_buffer
    }

    ~fixed_vector()
    {
        // some way to suppress the automatic destruction of m_buffer
    }
};

int main()
{
    {
        fixed_vector<S, 100> arr;
    }

    std::cout << "Created:\t"   << created   << std::endl;
    std::cout << "Destroyed:\t" << destroyed << std::endl;
    return 0;
}
我希望是:

Created:    0
Destroyed:  0
我唯一的想法是制作
m_buffer
一些简单构造和解构的类型,如
char
,然后依靠
操作符[]
为我包装指针数学,尽管这似乎是一个骇人听闻的解决方案。另一个解决方案是使用
malloc
free
,但这提供了我不想要的间接层次


我之所以想要这样做,是因为我正在制作一个容器,我不想为我不想使用的东西的初始化开销买单。例如,如果我的
main
函数是:

int main()
{
    {
        std::vector<S> vec;
        vec.reserve(50);
    }

    std::cout << "Created:\t"   << created   << std::endl;
    std::cout << "Destroyed:\t" << destroyed << std::endl;
    return 0;
}

您可以看看STL容器的使用方式,但我怀疑您是否可以节省自己的
malloc
s和
free
s

此代码:

#include <iostream>
#include <vector>
using namespace std;

int created = 0, destroyed = 0;

struct S
{
    S()
    {
        ++created;
    }
    S(const S & s ) {
        ++created;
    }
    ~S()
    {
        ++destroyed;
    }
};

int main()
{
    {
        std::vector<S> vec;
        vec.reserve(50);
    }

    std::cout << "Created:\t"   << created   << std::endl;
    std::cout << "Destroyed:\t" << destroyed << std::endl;
    return 0;
}
#包括
#包括
使用名称空间std;
创建的int=0,销毁的int=0;
结构
{
S()
{
++创造;
}
S(施工S&S){
++创造;
}
~S()
{
++摧毁;
}
};
int main()
{
{
std::vec;
车辆储备(50);
}

std::cout您可以将数组创建为
char
s的数组,然后在需要时使用创建元素

template <typename T, size_t KCount>
class Array
{
private:
    char m_buffer[KCount*sizeof(T)]; // TODO make sure it's aligned correctly

    T operator[](int i) {
        return reinterpret_cast<T&>(m_buffer[i*sizeof(T)]);
    }
模板
类数组
{
私人:
char m_buffer[KCount*sizeof(T)];//确保正确对齐
T运算符[](int i){
返回reinterpret_cast(m_buffer[i*sizeof(T)]);
}

在重读您的问题之后,您似乎想要一个稀疏数组,这有时被称为map;o(当然性能特征是不同的…)

模板
类散斑鱼{
std::map mu map;
公众:
T&T操作员[](尺寸i){
如果(i>KCount)
抛出“出界”;
返回m_图[i];
}

您可能需要查看
boost::optional

template <typename> struct tovoid { typedef void type; };

template <typename T, size_t KCount, typename = void>
struct ArrayStorage {
  typedef T type;
  static T &get(T &t) { return t; }
};

template <typename T, size_t KCount>
struct ArrayStorage<T, KCount, typename tovoid<int T::*>::type> {
  typedef boost::optional<T> type;
  static T &get(boost::optional<T> &t) {
    if(!t) t = boost::in_place();
    return *t;
  }
};

template <typename T, size_t KCount>
class Array
{
public:
    T &operator[](std::ptrdiff_t i) {
      return ArrayStorage<T, KCount>::get(m_buffer_[i]);
    }

    T const &operator[](std::ptrdiff_t i) const {
      return ArrayStorage<T, KCount>::get(m_buffer_[i]);
    }

    mutable typename ArrayStorage<T, KCount>::type m_buffer_[KCount];
};

如果你想成为向量,你应该这样做:

template <typename T>
class my_vector
{
    T* ptr; // this is your "array"
    // ...
    public:

    void reserve(size_t n)
    {
        // allocate memory without initializing, you could as well use malloc() here
        ptr = ::operator new (n*sizeof(T)); 
    }

    ~my_vector()
    {
        ::operator delete(ptr); // and this is how you free your memory
    }

    void set_element(size_t at, const T& element = T())
    {
        // initializes single element
        new (&ptr[at]) T(element); // placement new, copies the passed element at the specified position in the array
    }

    void destroy_element(size_t at)
    {
        ptr[at].~T(); // explicitly call destructor
    }
};
模板
给我的向量分类
{
T*ptr;//这是您的“数组”
// ...
公众:
无效储备(大小)
{
//在不初始化的情况下分配内存,您也可以在这里使用malloc()
ptr=::运算符new(n*sizeof(T));
}
~my_vector()
{
::operator delete(ptr);//这就是释放内存的方法
}
空集元素(大小为,常数为&element=t())
{
//初始化单个元素
new(&ptr[at])T(element);//placement new,将传递的元素复制到数组中的指定位置
}
无效销毁元素(大小为)
{
ptr[at]。~T();//显式调用析构函数
}
};
这段代码显然只是为了演示,我省略了我的_向量的复制构造函数,以及对创建内容和未创建内容的任何跟踪(在未调用构造函数的位置调用析构函数可能是未定义的行为)。此外,STL的
vector
分配和解除分配通过使用分配器(
vector
的第二个模板参数)进行抽象


希望这对你有所帮助

你到底为什么想要一个未构建的
S
实例数组?你能用它们做什么?没用——这就是问题所在。我已经用正当理由修改了我的问题。所以如果我理解正确,你想在向量中为以后填充的元素保留空间,而你不想为常量付费重建(和破坏)元素两次。这种性能差异真的那么重要吗?你分析过你的应用程序并验证过这是执行过程中花费时间最多的地方吗?你为什么不保留指针向量而不是对象向量呢?@Péter:我的问题更多地与没有无参数构造函数的对象构造有关。即使给出了解决方案,具有昂贵构造函数或没有赋值运算符的对象仍然是一个问题。我可以通过使用
char m_buffer[KCount*sizeof(T)]
来节省自己的
malloc
free
(虽然语义明显不同,因为这是不允许的)。他不能做
vec[1]
之后。(惰性构造)这是正确的(如我的问题中所述),但是
std::vector
是如何做到这一点的呢?通过g++的实现,看起来他们对
char[]进行了大量的
重新解释
避免初始化到最后一秒。@Travis vector创建未初始化的内存,然后根据需要使用placement new在其中创建实际对象。我在想
重新解释cast
,因为语义对我来说更有意义。但我真的希望避免这种情况——有什么方法不必这样做吗?你是是的,
static\u cast
是一个错误的选择,更新我的答案。你的第一个解决方案就是我想要的,基本上就是我想要的。请注意:你想重新解释
T&
而不是
T
@Travis,请注意,你必须安排好与此代码的正确对齐。很可能不是在没有任何额外工作的情况下,
Array a;
没有正确对齐,并且在某些平台上(例如在sun sparc、iirc上)会随机崩溃。还请注意,您同样需要为此设置标志(这基本上也是我在解决方案中所做的)。否则,你无法决定什么时候新建,什么时候不新建。我想,为了简洁起见,代码被省略了。无论如何,如果你喜欢它的样子,那就玩吧。毕竟这是你的代码:)我实际上使用了
return reinterpret_cast(m_buffer)[i]
,因为它看起来更干净。但我忘记了正确的对齐方式-很好的捕获。这是
template <typename T, size_t KCount>
class SparseArray {
    std::map<size_t, T> m_map;
public:
    T& operator[](size_t i) {
        if (i > KCount)
            throw "out of bounds";
        return m_map[i];
    }
template <typename> struct tovoid { typedef void type; };

template <typename T, size_t KCount, typename = void>
struct ArrayStorage {
  typedef T type;
  static T &get(T &t) { return t; }
};

template <typename T, size_t KCount>
struct ArrayStorage<T, KCount, typename tovoid<int T::*>::type> {
  typedef boost::optional<T> type;
  static T &get(boost::optional<T> &t) {
    if(!t) t = boost::in_place();
    return *t;
  }
};

template <typename T, size_t KCount>
class Array
{
public:
    T &operator[](std::ptrdiff_t i) {
      return ArrayStorage<T, KCount>::get(m_buffer_[i]);
    }

    T const &operator[](std::ptrdiff_t i) const {
      return ArrayStorage<T, KCount>::get(m_buffer_[i]);
    }

    mutable typename ArrayStorage<T, KCount>::type m_buffer_[KCount];
};
// only two strings are constructed
Array<std::string, 10> array = { a, b };
template <typename T>
class my_vector
{
    T* ptr; // this is your "array"
    // ...
    public:

    void reserve(size_t n)
    {
        // allocate memory without initializing, you could as well use malloc() here
        ptr = ::operator new (n*sizeof(T)); 
    }

    ~my_vector()
    {
        ::operator delete(ptr); // and this is how you free your memory
    }

    void set_element(size_t at, const T& element = T())
    {
        // initializes single element
        new (&ptr[at]) T(element); // placement new, copies the passed element at the specified position in the array
    }

    void destroy_element(size_t at)
    {
        ptr[at].~T(); // explicitly call destructor
    }
};