2008-12-16 2 views
5

Я реализую математическую библиотеку на C++. Библиотека будет скомпилирована в DLL, поэтому те, кто ее использует, будут нуждаться только в файлах заголовков определения классов.Ссылка на C++

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

Я хочу сделать что подсчет ссылок как можно более прозрачным, к примеру ...

// Define a Bézier curve 
CVecList pts; 
pts.Add(Vector(0,0,0)); 
pts.Add(Vector(0,0,100)); 
pts.Add(Vector(0,100,0)); 
pts.Add(Vector(0,100,100)); 
CCurve* c1 = new CBezier(pts); 

// Define a 3rd order B-Spline curve 
pts.Clear(); 
pts.Add(Vector(0,0,0)); 
pts.Add(Vector(0,200,100)); 
pts.Add(Vector(0,200,200)); 
pts.Add(Vector(0,-200,100)); 
pts.Add(Vector(0,-200,200)); 
pts.Add(Vector(0,0,0)); 
CCurve* c2 = new CBSpline(pts,3); 

// The Bézier curve object must be deleted automatically 
// because the only reference to it has been released 
// Similar to IUnknown::Release() in COM 
c1 = c2; 

Все становится немного сложнее, когда я определяю объекты на поверхности, потому что некоторые поверхности определяются в терминах два кривые:

CVecList pts; 
// ... 
CCurve* f = new CBezier(pts); 

pts.Clear(); 
// ... 
CCurve* g = new CBezier(pts); 

// Mixed surface: S(u,v) = (1-v)*f(u) + v*g(u) 
CSurface* s = new CMixed(f,g); 

// There are two references to the first Bézier curve, 
// the first one is f 
// the second one is hidden in a member of CMixed 

// Something similar applies to the second Bézier curve 

Я думал, что переопределение operator = для указателей могли бы помочь:

// This is what I tried, but it's illegal: 
typedef CReferenceCounted* PRC; 
PRC& operator =(PRC& dest, PRC& source) 
{ 
    if (source) 
     source->AddRef(); 
    if (dest) 
     dest->Release(); 
    memcpy(&dest,&source,sizeof(PRC)); 
    return dest; 
} 

... но затем я обнаружил, что operator = недействителен, если он не является нестационарным членом класса.

Может ли кто-нибудь мне помочь?

+0

http://ootips.org/yonat/4dev/smart-pointers.html – derobert 2008-12-16 05:10:44

+0

Я пытался сохранить свой код-шаблон бесплатно, но я не могу найти другое решение. Спасибо. – 2008-12-16 05:22:57

ответ

11

Что вы пытались перегрузить оператора для скалярных типов. C++ не позволяет вам это делать, кроме перечислений (помимо того, что оператор = должен быть членом). По крайней мере один из типов должен быть определяемым пользователем типом. Таким образом, то, что вы хотите сделать, - это обернуть необработанный указатель в пользовательский класс, который перегружает конструктор, конструктор копирования, оператор назначения копирования и деструктор и выполняет правильный подсчет ссылок. Это идеальная ситуация для boost::shared_ptr, которая делает именно то, что:

boost::shared_ptr<CCurve> c1(new CBezier(pts)); 

То же дело с поверхностями:

CVecList pts; 
// ... 
boost::shared_ptr<CCurve> f(new CBezier(pts)); 

pts.Clear(); 
// ... 
boost::shared_ptr<CCurve> g(new CBezier(pts)); 

// Mixed surface: S(u,v) = (1-v)f(u) + vg(u) 
boost::shared_ptr<CSurface> s(new CMixed(f,g)); 

Карри вокруг этого смарт-указатель, и он будет автоматически управлять время жизни из указывает на объект: если последняя копия указателя выходит за пределы области действия, объект, на который указывает, освобождается. shared_ptr разработан для удобства использования. Старайтесь избегать работы с необработанными указателями столько, сколько сможете. Посмотрите на эти умные указатели, они облегчат ваши программисты живут с C++ :)

Edit: Если вы собираетесь обернуть shared_ptr, вы можете сделать это с помощью Pimpl (ручка/тело) идиома:

/* ---- wrapper in header file bezier.hpp */ 

struct CBezier { 
    CBezier(CVecList const& list); 
    void do_calc(); 
    // ... 

private: 
    struct CBezierImpl; 
    boost::shared_ptr<CBezierImpl> p; 
}; 

/* ---- implementation file bezier.cpp */ 

// private implementation 
struct CBezier::CBezierImpl { 
    CBezierImpl(CVecList const& list); 
    void do_calc(); 
    // ... 
}; 


CBezier::CBezier(CVecList const& list) 
:p(new CBezierImpl(list)) { 

} 

void CBezier::do_calc() { 
    // delegate to pimpl 
    p->do_calc(); 
} 

// ... 
0

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

1

Если вы разрабатываете математическую библиотеку, потратьте много времени на размышления, могут ли ваши классы выглядеть как int или std :: complex. То есть, ценности ведут себя как значения. Например.

std::vector<math::point3d> pts; 
pts.push_back(math::point3d(0,0,0)); 
pts.push_back(math::point3d(110,0,0)); 
pts.push_back(math::point3d(0,100,0)); 
pts.push_back(math::point3d(0,0,100)); 
CCurve c1 = make_bezier(pts); 
0

Пользователи моих классов будут люди, которые являются новыми для языка.

Является ли ваш класс предназначенным для программирования?

Если это так, то я хотел бы избежать использования указателей и использовать только конструкторы копирования/ассигнование:

  • Производительность/Память не является приоритетом
  • Doing управление памятью себя покажет очень плохой пример о том, как использовать new/delete
  • Использование любого интеллектуального указателя, не зная об управлении памятью, может вызвать много путаницы позже.
0

Я согласен с Guishu и MSalters. Даже если это не для курса программирования, может быть неплохо подражать более близкому математическому взгляду (например, vector3 = vector1 + vector2 и т. Д.).

Вы также можете использовать copy-on-write (подтверждение того, что это логическое следствие), но только внутренне. Это может дать вам достаточно быстрые задания, исключить управление кучей на стороне клиента и сходство с математической нотацией.

Обратите внимание, что для C++ существуют математические библиотеки (TNT, с верхней части головы). Вы считаете, что основываете свою работу на этом?