如何在创建对象数组时避免使用默认构造函数?

时间:2012-01-04 22:39:09

标签: c++

我在这里很新,所以我对这里的写作风格不是很熟悉,如果问题看起来不应该,那就很抱歉。 我的问题是,如何创建一个对象数组,而不是默认的构造函数? 如果我有这样的事情:

set<movie> a(3);
set<movie> b(2);

和构造者: 对于电影

movie::movie()
{
    this->naziv=0;
    this->reditelj=0;
    this->trajanje=0;
}

movie::movie(char *name, char *red, int len)
{
    this->naziv=new char[strlen(name)+1];
    strcpy(naziv,name);
    this->reditelj=new char[strlen(red)+1];
    strcpy(reditelj,red);
    this->trajanje=len;
}

对于集合:

template<class t>
set<t>::set()
{
    this->br=0;
    this->niz=0;
}

set<t>::set(int b)
{
    this->br=b;
    this->niz=new t[br];
}

答案很棒,但是当然他们教我们一些关于c ++的基本知识,如何创建类,模板类,我的意思是,从头开始编写程序,所以现在我们不使用那些类和函数大多数人都提到过。赋值是以这种方式编写代码,那么我该怎么做呢? 赋值是创建一个类和一个模板类,模板类实际上是一个对象数组,所以我应该创建一个对象,这是一个对象数组,以及一些其他函数。

这是我的整个代码:

Set.h

#pragma once
#include<iostream>
using namespace std;

template<class t>
class set
{
    int br;
    t* niz;
public:
    set();
    set(int b);
    ~set();
    set(set& copy);
    int vrati_br_elem()
    {
        return br;
    }
    bool pripada(t elem);
    set operator*(set& drugi);
    friend istream& operator>> <>(istream& ulaz,set<t> &s);
    friend ostream& operator<< <>(ostream& izlaz,set<t> &s);
};

template<class t>
set<t>::set()
{
    this->br=0;
    this->niz=0;
}

template<class t>
set<t>::set(int b)
{
    this->br=b;
    this->niz=new t[br];
}

template<class t>
set<t>::~set()
{
    if(this->niz!=0)
        delete [] niz;
}

template<class t>
bool set<t>::pripada(t elem)
{
    for(int i=0;i<this->br;i++)
        if(this->niz[i]=elem)
            return true;
    return false;
}

template<class t>
set<t> set<t>::operator *(set<t> &drugi)
{
    int broj=0;
    set<t> pom((this->br>drugi.br)?this->br:drugi.br);
    for(int i=0;i<this->br;i++)
        for(int j=0;j<drugi.br;j++)
            if(this->niz[i]==drugi.niz[j])
                pom.niz[broj++]=this->niz[i];
    pom.br=broj;
    return pom;
}

template<class t>
istream& operator>>(istream& ulaz,set<t> &s)
{
    for(int i=0;i<s.br;i++)
        cin>>s.niz[i];
    return ulaz;
}

template<class t>
ostream& operator<<(ostream& izlaz,set<t> &s)
{
    for(int i=0;i<s.br;i++)
        cout<<endl<<s.niz[i]<<endl;
    return izlaz;
}

template<class t>
set<t>::set(set<t> &copy)
{
    this->br=copy.br;
    this->niz=new t[br];
    for(int i=0;i<this->br;i++)
        this->niz[i]=copy.niz[i];
}

movie.h

#include<iostream>
using namespace std;

class movie
{
    char* naziv;
    char* reditelj;
    int trajanje;
public:
    movie();
    ~movie();
    movie(movie& copy);
    movie(char* name,char* red,int len);
    movie& operator=(movie& film);
    bool operator==(movie& film);
    friend istream& operator>>(istream& ulaz,movie& film);
    friend ostream& operator<<(ostream& izlaz,movie& film);
};

movie.cpp

#include"movie.h"
using namespace std;

movie::movie()
{
    this->naziv=0;
    this->reditelj=0;
    this->trajanje=0;
}

movie::~movie()
{
    if(naziv!=0&&reditelj!=0)
    {
        delete [] naziv;
        delete [] reditelj;
    }
}

movie::movie(movie &copy)
{
    this->naziv=new char[strlen(copy.naziv)+1];
    strcpy(this->naziv,copy.naziv);
    this->reditelj=new char[strlen(copy.reditelj)+1];
    strcpy(this->reditelj,copy.reditelj);
    this->trajanje=copy.trajanje;
}

movie& movie::operator =(movie &film)
{
    if(this!=&film)
    {
        delete [] naziv;
        delete [] reditelj;

        this->naziv=new char[strlen(film.naziv)+1];
        strcpy(this->naziv,film.naziv);
        this->reditelj=new char[strlen(film.reditelj)+1];
        strcpy(this->reditelj,film.reditelj);
        this->trajanje=film.trajanje;
    }
    return *this; 
}

bool movie::operator ==(movie &film)
{
    if(!strcmp(this->naziv,film.naziv)&&!strcmp(this->reditelj,film.reditelj)&&this->trajanje==film.trajanje)
        return true;
    return false;
}

istream& operator>>(istream& ulaz,movie& film)
{
    ulaz>>film.naziv>>film.reditelj>>film.trajanje;
    return ulaz;
}

ostream& operator<<(ostream& izlaz,movie& film)
{
    izlaz<<endl<<film.naziv<<endl<<film.reditelj<<endl<<film.trajanje<<endl;
    return izlaz;
}

movie::movie(char *name, char *red, int len)
{
    this->naziv=new char[strlen(name)+1];
    strcpy(naziv,name);
    this->reditelj=new char[strlen(red)+1];
    strcpy(reditelj,red);
    this->trajanje=len;
}

6 个答案:

答案 0 :(得分:2)

不要使用内置数组,特别是如果你是新的。内置阵列最好留给专家,即使这样,他们通常最好避免使用。而不是使用T[n]而只使用std::vector<T>。这个将开始空,你可以然后例如push_back()您感兴趣的对象。

那就是说,我没看到你的代码摘录实际上有问题。

答案 1 :(得分:1)

您可以创建一个直接调用构造函数的对象数组。

movie objs[2] = {movie(arg1, arg2, arg3), movie(arg1, arg2, arg3)};

答案 2 :(得分:1)

执行此操作的标准方法是使用分配器对象,就像所有标准容器一样。

template<class T, class alloc_type =std::allocator<T> >
class set {
     typedef alloc_type::pointer pointer; //bring in it's pointer type
     alloc_type alloc;

然后,将其用于所有事情:

pointer buffer = alloc.allocate(100);
alloc.construct(buffer+0); //deault construct T
alloc.construct(buffer+1, T()); //construct T from copy
alloc.construct(buffer+2, 17); //construct T from 17

alloc.destroy(buffer+2);  //clean up objects
alloc.destroy(buffer+1); 
alloc.destroy(buffer+0); 
alloc.deallocate(buffer); //clean up buffer

请记住,从最低索引到最高索引进行构造是标准的,并且以相反的顺序进行破坏。

使用C ++ 11改变了“正确”的方法,但由于我使用了MSVC10,不能以正确的方式行事,我仍然使用这种方式。

但是,每个函数的基本实现都非常简单。

template<class T>
class myallocator {
public:
    typedef T value_type;
    typedef T* pointer;
    typedef T& reference;
    typedef const T* const_pointer;
    typedef const T& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    myallocator () throw() {}
    template <class U> myallocator (const myallocator<U>&) throw() {}
    pointer address (reference x) const {return &x;}
    const_pointer address (const_reference x) const {return &x;}
    size_type max_size() const throw() {return size_type(-1);}

pointer allocate(size_type c,const_pointer h=0){return(T*)new char[sizeof(T)*c];}
    void deallocate(pointer ptr, size_type c) {delete [] ptr;}
    pointer construct(pointer ptr) {return new(ptr)T;}
    template<class U>
    pointer construct(pointer ptr, const U& from) {return new(ptr)T(from);}
    void destroy(pointer ptr) {ptr->~T();}
};

两个construct成员使用所谓的“placement new”,它在已有空间中创建对象。这是一个char s。

的数组

答案 3 :(得分:0)

您正在尝试编写自己的容器类,而不应将其称为set。我会假设你在这个答案中称之为my_set

我认为这是您感兴趣的行。您希望在此处传递默认值:

my_set<t>::my_set(int b, t default_value)
//creates a my_set with 'b' elements, where each element is set to default_value

这是你的目标吗?如果是这样,则可以更轻松地将niz定义为*vector<t>而不是t*

template<class t>
struct my_set {
    int br;
    vector<t> *niz;
    my_set(int b, const t& default_value);
}

template<class t>
my_set<t>::my_set(int b, const t& default_value) {
//creates a my_set with 'b' elements, where each element is set to 0
    this->br=b;
    this->niz=new vector<t>(b, default_value);
}

您可以考虑进行其他更改,例如将niz定义为vector<t>,而不是vector<t>*,但我认为这超出了原始问题的范围。

最后,我对每个人都有自己的问题。如何在C ++中执行未初始化的数组new[]?我想new一个已知大小的数组,但是使用未构造的数据,然后使用uninitialized_copy之类的东西来复制数据。

答案 4 :(得分:0)

表达式new T[n]将始终为 n T个对象分配空间,并在每个元素上调用T构造函数。同样,delete[] niz将始终在每个元素上调用T析构函数。您似乎想要手动控制何时调用T构造函数和析构函数,因此您可以使用::operator new[]及其放置语法,而不是使用::operator new

您希望niz成为br T个对象的数组。而不是:

niz = new T[br];

您可以使用:

niz = static_cast<T *>(::operator new(br * (sizeof (T))));

将为br个连续T个对象分配堆中的空间,但不会在其中任何一个上调用T构造函数。它基本上就像使用malloc()T对象分配空间。

但是,现在你遇到了一个问题:你如何实际使用其中一个T个对象?在使用niz[i]执行任何操作之前,您需要确保已构造 i th T对象。您可以使用placement new来构建它:

new(niz + i) T();

请注意niz + i是指向 i th T对象的指针。此声明的效果是使用Treinterpret_cast<char *>(niz + i)的空格调用reinterpret_cast<char *>(niz + i) + (sizeof (T))构造函数。

现在您还有另一个问题:如何跟踪已构建的T个对象?你需要知道这一点,以便在已经构造的析构函数上调用析构函数,否则你可能会泄漏内存。

一种解决方案是使用std::vector<bool>br bool个对象。如果 i th booltrue,那么您将知道 i th T对象构建完毕。否则,需要构建它。

set<T>析构函数中,您需要确保销毁已构造的所有T个对象。假设已经构造了 i th T对象。要在 i th T对象上调用T析构函数,可以使用以下语句:

(niz + i)->~T();

总而言之,你会得到这样的东西:

#include <cstddef>
#include <iostream>
#include <new>
#include <vector>

template <typename T>
class set
{
    std::size_t br;
    T *niz;
    std::vector<bool> constructed;

public:
    std::string name;

    set()
        : br(0), niz(NULL), constructed()
    {
    }

    set(std::size_t br)
        : br(br), niz(NULL), constructed(br, false)
    {
        niz = static_cast<T *>(::operator new(br * (sizeof (T))));
    }

    void destroy()
    {
        std::cout << "~set(" << name << ")\n";

        if (niz) {
            std::vector<bool>::const_iterator begin = constructed.begin(), it, end = constructed.end();
            for (it = constructed.begin(); it != end; ++it) {
                if (*it) {
                    (niz + (it - begin))->~T();
                }
            }
            ::operator delete(niz);
        }
    }

    ~set()
    {
        destroy();
    }

    set<T>& operator=(const set<T>& other)
    {
        if (this != &other) {
            destroy();
            niz = NULL;

            constructed = std::vector<bool>(other.br, false);
            br = other.br;
            T *tmp = static_cast<T *>(::operator new(other.br * (sizeof (T))));
            try {
                std::size_t i;
                for (i = 0; i < other.br; ++i) {
                    if (other.constructed[i]) {
                        new(tmp + i) T(other.niz[i]);
                        constructed[i] = true;
                    }
                }
            } catch (...) {
                niz = tmp;
                destroy();
                throw;
            }
            niz = tmp;
            name = other.name + " (2)";
        }
        return *this;
    }

    T& operator[](std::size_t i)
    {
        if (niz && !constructed[i]) {
            new(niz + i) T();
            constructed[i] = true;
        }
        return niz[i];
    }
};

struct my_struct
{
    char c;

    my_struct(char c = 'a')
        : c(c)
    {
        std::cout << "my_struct('" << c << "')\n";
    }

    ~my_struct()
    {
        std::cout << "~my_struct('" << c << "')\n";
    }
};

int main()
{
    ::set<char> a, a2(3);
    a.name = "a";
    a2.name = "a2";

    {
        ::set<my_struct> b(3);
        b.name = "b";
        b[0].c = '1';
        b[2].c = '3';
        b[1].c = '2';

        ::set<my_struct> b2(4);
        b2.name = "b2";
        b = b2; b.name += ", going by the name 'b'";

        b[0].c = 'A';
        b2[1].c = 'B';
    }
}

注意:我不建议实际使用此代码。关键是要了解placement new运算符并通过指针显式调用析构函数。

有关标准替代方案,请参阅STL模板vectorset

答案 5 :(得分:0)

您的代码中的一个问题是,如果任一字符串为0

,则会失败
ostream& operator<<(ostream& izlaz,movie& film)
{
    izlaz
        << endl << film.naziv // fails if film.naziv == 0
        << endl << film.reditelj  // fails if film.reditelj == 0
        << endl << film.trajanje << endl;
    return izlaz;
}

对我而言崩溃了。你不应该cout << (char*)0;。最好做cout << ""之类的事情。您可以通过更改movie的构造函数来修复它:

movie::movie()
{
    this->naziv="";    // an empty, non-null, string
    this->reditelj=""; // an empty, non-null, string
    this->trajanje=0;
}

但更好的解决方案是停止使用char *并改为使用std :: string