2012-07-02 2 views
0

У меня есть код:Сложные аргументы в C++ -функциях - Указатели, refenreces или ...?

class Vector3D : public Vector{ 
protected: 
    Point3D * start; 
    Point3D * end; 

public: 
    ~Vector3D(){delete start; delete end;} 
    Vector3D(Point3D * start, Point3D * endOrLength, bool fromLength){ 
     this->start = start; 
     if(fromLength){ 
      this->end = new Vector3D(*start+*endOrLength); //the operator '+' is defined but I won't put it here, 
      //because it's not important now 
     }else 
      this->end = endOrLength; 
    } 

    Point3D * getStart(){return start;} 
    Point3D * getEnd(){return end;} 
}; 

Теперь у меня есть код:

Vector3D v(new Point3D(1,2,3), new Point3D(2,3,4), 0); //FIRST CREATION 
Vector3D v(new Point3D(1,2,3), new Point3D(1,1,1), 1); //SECOND CREATION 

Первое и второе творение дают мне то же самое Vector3D, но я думаю, что это может привести к утечке памяти.

Это правда? И как его решить? Я предполагаю, что это не элегантно, чтобы сделать это таким образом:

... 
if(fromLength){ 
    this->end = new Vector3D(*start+*endOrLength); 
    delete endOrLength; 
}else 
... 

Может, лучше поставить Const Point3d & endOrLenght, я не знаю, что было бы хорошо mannier? То же самое с getStart/getEnd - она должна возвращать указатель:

Point3D * getStart(){return start;} 

или просто переменная:

Point3D getStart()(return *start) 

?

ответ

2

Вы здесь код не может быть лучшим способом обработки, но непосредственно исправить вашу проблему:

Vector3D(Point3D * start, Point3D * endOrLength, bool fromLength){ 
    this->start = start; 
    if(fromLength){ 
     this->end = new Vector3D(*start+*endOrLength); // I think you mean to use endOrLength here and not length. 
     if (endOrLength) 
      delete endOrLength; 
    }else 
     this->end = endOrLength; 
} 

Я думаю, лучшее решение вашей проблемы является использование смарт-указатели, и Лучшее решение - посмотреть, можете ли вы заменить указатели.

class Vector3D : public Vector 
{ 
protected: 
    Point3D _start; 
    Point3D _end; 

public: 
    Vector3D(const Point3D& start, const Point3D& endOrLength, bool fromLength) : 
    _start(start), 
    _end(fromLength ? Vector3D(start + endOrLength) : endOrLength) 
    { 
    } 

    const Point3D& getStart() const { return _start; } 
    const Point3D& getEnd() const { return _end; } 
}; 
+0

Спасибо, это исправит проблему с кодом, но, как вы сказали, мой код не самый лучший способ. – PolGraphic

+1

@PolGraphic Я обновил свой ответ, но я не уверен, можете ли вы его использовать. –

+0

Да, вот и все! Спасибо :-) – PolGraphic

1

Я думаю, что правильный путь:

Vector3D(const Point3D& start, const Point3D& endOrLength, bool fromLength) 

Таким образом, нет никакой двусмысленности в собственность. Кроме того, члены, вероятно, не должны быть указателями, иначе это может привести к оборванным указателям, а скорее к элементам данных.

Или даже лучше, умные указатели.

Если вы используете интеллектуальные указатели, вы можете вернуть умный указатель из функции get.

+0

и использовать Point3D getStart() {возвращение старт; } как возвращение действительно. Или, возможно, это Point3D, и если у вас есть более старый компилятор (или даже сделать его const Point3D, и если вы хотите быть уверенным, что точка не будет изменена) – Sander

+1

приложение будет лучше и проще, если что-то основное, как точка может быть передана по значению, а не как shared_ptr – stijn

+0

Я вижу, я буду использовать const & – PolGraphic

3

Прежде всего, я бы не динамически выделял объекты ценности, как трехмерная точка. Просто используйте значения, которые могут сэкономить вам массу неприятностей. Во-вторых, если у вас есть два способа построить свой вектор, просто обеспечивают два различных конструктора:

class Vector3D { 
public: 
    Vector3D(const Point3D& s, const Point3D& e) 
     : start(s) 
     , end(e) 
    { 
    } 

    Vector3D(const Point3D& s, const Vector3D& v) 
     : start(s) 
     , end(s + v) 
    { 
    } 
} 
private: 
    Point3D start; 
    Point3D end; 
}; 

Имея функцию, которая делает две разные вещи в зависимости от параметра функции даже трудно понять с вызывающей стороны. Просто трудно вспомнить, для чего это было последним 1 или 0.

Уважение, Торстен

+0

Спасибо большое :-) – PolGraphic

1

Ваш дизайн может быть менее эффективным, как это может показаться, так как она, как правило, по самой своей природе (каждый элемент выходит, как изолированный) нарушать местности на операции. Копирование между вещами, которые вместе, может быть намного более эффективным, чем операция по разыменованию редких вещей.

И так как ваш вектор - это просто .... 2 * 3 номера, избегайте всех усложнений динамической памяти и просто используйте семантику нормального значения.

Если вы достигли объекта с большими размерами (например, матрицами трехмерных проекций, которые могут иметь до 16 коэффициентов), рассмотрите идею обработки динамической памяти только для внутреннего класса. В вашем случае это может быть как

class Vector3d 
{ 
    struct data 
    { Point3d start, end; }; 

    Vector3d() :dp(new data) {} 
    Vector3d(const Point3d& a, const Point3d& b) :p(new data({a,b})) {} 

    Vector3d(const Vector3d& a) :p(new data(*a.p)) {} 
    Vector3d(Vector3d&& a) :p(a.p) { a.p=nullptr; } 
    Vector3d& operator=(Vector3d a) { delete p; p=a.p; a.p=nullptr; return *this; } 
    ~Vector3d() { delete p; } 

    const Poin3d& start() const { return p->start; } 
    const Poin3d& end() const { return p->end; } 

    //here define the compound assignment arithmetic 
    //e.g.: 
    Vector3d& operator+=(const Point3d& ofst) 
    { p->start += ofst; p->end += ofst; return *this; } 

    //alternativelly you can define assign in term of arithmetic 
    Vector3d& operator-=(const Poinr3d& ofst) 
    { *this = *this - ofst; return *this; } //will create a temporary that will be moved 

private: 
    data* p; 
}; 

//and here define the point3d, vectopr3d and mixed arithmetic 
//e.g.: 
Vector3d operator+(Vector3d a, const Point3d& s) 
{ a += s; return std::move(a); } 

//this follow the alternative example 
Vector3d operator-(const Vecotr3d& a, const Point3d& s) 
{ return Vector3d(a.start()-s, a.end()-s); } 

Таким образом, все управление динамической памяти, а также генерация copyes (при необходимости) или движется (где это возможно) остались в классе. Все остальное работает со стандартной семантикой значений.

Примечание: Я предположил, Poin3d имеет + = - = + и - определяется ....

+0

Это отличная идея. Извините, что я могу отметить только один ответ как «принятый anserw». К счастью, я могу проголосовать за полезный anserw :-) – PolGraphic

+0

Если использовать C++ 11, я бы предложил полностью избежать ручного управления памятью и просто использовать 'std :: unique_ptr'. Делает операции копирования/перемещения-конструкторы/деструкторы/присваивания еще проще (и проще получить право на безопасность исключений). Единственное исключение - если пространство или время выполнения чрезвычайно критичны, но в этом случае, вероятно, лучше избегать распределения динамической памяти на основе каждого объекта (например, вместо этого использовать пул перераспределенных «данных»). – Grizzly

+0

@Grizzly: Разница в том, что unique_ptr может принимать «deleter», поэтому ему нужно добавить дополнительную память для хранения, по крайней мере, еще одного указателя времени выполнения для полиморфного внутреннего объекта. Хорошие реализации могут избежать этого, если не задан делетер. О пуле, поскольку данные могут быть необходимы и больше не нужны в любое время, вам нужно управлять пулами, позволять каждому данным (или владельцу данных) знать, какой пул принадлежит, и вам нужно отслеживать, какие данные внутри poo в использовании или может использоваться повторно. Это может занять в глобальном масштабе больше места и, в конце концов, в репликации ... (следует) –

Смежные вопросы