2012-01-04 89 views
2

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

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; 
} 
+0

'std :: allocator',可能用'std :: uninitialized_copy'或'std :: uninitialized_fill'。 – 2012-01-04 22:43:03

+2

另外,不要将你的班级命名为'set',否则你会迷惑每个人。 'std :: set'比你所做的更为人所知。另外,欢迎来到堆栈溢出。 – 2012-01-04 22:43:55

+1

您是否尝试使构造函数为私有?顺便说一句。你的问题格式很好:-) – rekire 2012-01-04 22:44:26

回答

1

可以创建对象的数组调用构造函数directl年。

movie objs[2] = {movie(arg1, arg2, arg3), movie(arg1, arg2, arg3)}; 
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成员使用所谓的“新布局”,这在已经存在的空间创建的对象。这里是一列char s。

+0

我不知道如何分配器的工作,但我约99.9%确定'T + 0'和所以不正确... – 2012-01-04 22:51:34

+0

哦jeez,'缓存+ 0',而不是'T + 0'。 – 2012-01-04 23:00:27

2

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

这么说,我没有看到你的代码摘录实际上有一个问题。

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在数据复制。

0

表达new T[n]将永远为ňT对象分配空间,并调用T构造在每个元素上。同样,delete[] niz,将始终在每个元素上调用T析构函数。看来你希望在T构造函数和析构函数被调用,因此而不是使用::operator new[],你可以只使用::operator new及其位置语法手动控制。

你想要niz是一个数组brT对象。取而代之的是:

niz = new T[br]; 

您可以使用此:

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

将在堆中分配空间br连续T对象,而不是呼吁任何人的T构造。这基本上就像使用malloc()T对象分配空间。

但是,现在你有一个问题:你如何实际使用T对象之一?之前,你可以用niz[i]做任何事情,你需要确保的是,T对象已建成。您可以使用新的布局来构建它:

new(niz + i) T(); 

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

现在你还有一个问题:你如何跟踪哪个对象被构建?你需要知道这个是为了调用那些已经构造的析构函数,否则你可能会泄漏内存。

一种解决方案是使用具有std::vector<bool>brbool对象。如果booltrue,那么你就会知道,我T对象构建。否则,它需要构建。

set<T>析构函数,你需要确保摧毁已建成的所有T对象。假设ithT对象已被构建。为了呼吁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'; 
    } 
} 

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

有关标准备选方案,请参见STL模板vectorset

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() 
{ 
    this->naziv=""; // an empty, non-null, string 
    this->reditelj=""; // an empty, non-null, string 
    this->trajanje=0; 
} 

但更好的方法是停止使用char *,并使用std :: string来代替。

相关问题