Wskaźniki C++ 14

0

Witam

Do tej pory pisałem w języku C++ proste programy. Teraz chciałbym napisać coś bardziej zaawansowanego. Dlatego zanim zacznę chciałbym poradzić się bardziej doświadczonych w tym względzie osób. Przeczytałem kilka książek i wymyśliłem sobie taką koncepcję:



/////////////////////////////////////Jakiś obiekt
class Obiekt
{
public:
	...
	void rysuj();
	...
}

/////////////////////////////////////Klasa przechowująca obiekty
class Pojemnik
{
	public:
	…
	void dodajObiekt();
	std::shared_ptr zwróćObiekt();
	….
	private:
	std::vector<std::shared_ptr<Obiekt>> pojObiektów;

}

void Pojemnik::dodajObiekt()
{
	Obiekt temp;
	std::shared_ptr<Obiekt> spw1;
	… //jakieś tam wypełnianie danymi itp.
	
	 spw1 = std::make_shared<temp>;
	pojObiektów.push_back(spw1);
}

/////////////////////////////////////Klas która wyświetla obiekty
class InnaKlasa
{
	public:
	…
	void rysujObiekty();
	…
	
}

void InnaKlasa::rysujObiekty()
{
	std::shared_ptr<Obiekt> spw1;

	spw1 = Pojemnik.zwróćObiekt(index);

	 spw1->rysuj();
}

Pytania:
Czy w ten sposób nie „zgubi” się po drodze obiekt?
Czy takie podejście jest prawidłowe?

0

Jeśli klasa ma być właścicielem obiektu i go "oddawać", wystarczy unique_ptr a nie shared_ptr.

0

Rozumiem, że shared_ptr tworzyć jak będę z tej klasy chciał przekazać do innej klasy wskaźnik na obiekt?

0

Chodzi o własność, jeśli zamierzasz zwrócić obiekt z tego vectora(w zamyśle usunąć go przy zwracaniu), użyj unique_ptr. Wtedy tam gdzie zwrócisz tego ptr będziesz miał własność. unique_ptr ma bardzo niski narzut.

0

Masz krótki przykład:

#include <iostream>
#include <memory>
#include <vector>
#include <string>

// Kadłubkowa klasa dla ilustracji.. 
struct MyClass {
    MyClass(const std::string& name_): name{name_} {}
    void info() const {
        std::cout << name << std::endl;
    }
private:
    std::string name;
};

// Jakiś kontener trzymający dane.
static std::vector<std::unique_ptr<MyClass>> data;

// Zwraca wskaźnik na element pod określonym indeksem.
// Jeśli indeks nieprawidłowy, wskaźnik pusty.
std::unique_ptr<MyClass> grabElement(size_t index) {
    std::unique_ptr<MyClass> answer;
    if(index < data.size()) {
        // Przeniesienie elementu.
        answer = std::move(data[index]);
        // Element pod danym indeksem usuwam z kontenera.
        data.erase(data.begin() + index);
    }
    return answer;
}

int main() {
    using namespace std::string_literals;
    // Kilka elementów dodane do kontenera...
    for(auto i = 0; i < 5; ++i) {
        // Tu można mieć uwagi ale dla ilustracji wystarczy... 
        data.emplace_back(new MyClass("object"s + std::to_string(i)));
    }
    auto val = grabElement(3);
    if(val) {
        val->info();
    }
}
0

Chodzi o to, że nie chce go usunąć z pojemnika. Tylko lub aż przekazać "go" innej klasie by mogła na nim pracować np. wyświetlić.

1

Można pobrać wskaźnik z std::unique_ptr metodą std::get.

0

To powinno wyglądać tak (nie chce mi się pisać opisu czemu):

class DrawContext;

class IDrawable
{
public:
    virtual ~IDrawable() {}
    virtual void draw(DrawContext *context) const = 0;
}

class Container : public IDrawable
{
public:
    .....
    void add(std::shared_ptr<IDrawable> item);

    template<class T, typename... Args>
    void add_emplace(Args&&... args) {
         add(std::make_shared<T>(std::forward<Args>(args)...));
    }
    .....
public:
    override void draw(DrawContext *context) const;

private:
    std::vector<std::shared_ptr<IDrawable>> mItemsToDraw;
}

void Container::add(std::shared_ptr<IDrawable> item)
{
    mItemsToDraw.emplace_back(std::move(item));
}

void Container::draw(DrawContext *context) const
{
    for (const auto item& : mItemsToDraw) {
          item->draw(context);
    }
}

class DrawOnSomething
{
public:
    explicit DrawOnSomething(std::shared_ptr<IDrawable> item);
    .....
    void drawNow();
    .....
private:
    std::shared_ptr<IDrawable> mItem;
}
 
void DrawOnSomething::DrawOnSomething(std::shared_ptr<IDrawable> item)
    : mItem(std::move(item))
{
}

void DrawOnSomething::drawNow()
{
     SomeDrawContext context;
 
     mItem->draw(&context);
 
     context.doSomethingWithResult();
}

auto container = std::make_shared<Container>();
auto drawer = std::make_shared<DrawOnSomething>(container);
container.add_emplace<Rectange>(0, 0, 800, 600, Color::blue);
container.add_emplace<Circle>(300, 400, 250, Color:red);

drawer->drawNow();

1 użytkowników online, w tym zalogowanych: 0, gości: 1