我在这里很新,所以我对这里的写作风格不是很熟悉,如果问题看起来不应该,那就很抱歉。 我的问题是,如何创建一个对象数组,而不是默认的构造函数? 如果我有这样的事情:
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> ©)
{
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 ©)
{
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 :(得分: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
对象的指针。此声明的效果是使用T
到reinterpret_cast<char *>(niz + i)
的空格调用reinterpret_cast<char *>(niz + i) + (sizeof (T))
构造函数。
现在您还有另一个问题:如何跟踪已构建的T
个对象?你需要知道这一点,以便在已经构造的析构函数上调用析构函数,否则你可能会泄漏内存。
一种解决方案是使用std::vector<bool>
个br
bool
个对象。如果 i th bool
为true
,那么您将知道 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模板vector
和set
。
答案 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
。