nie do końca const std::vector (modyfikowalne elementy)

0

Mam taki mały problem (ale najpierw kod żeby lepiej zrozumieć).

#include <vector>

class Foo {
public:
    Foo(int i) : i(i) {}
private:
    int i;
};

class Bar {
public:
    static const std::vector<Foo> foos;
};

const std::vector<Foo> Bar::foos{ Foo(0), Foo(1), Foo(2) };

class Qux {
public:
    Qux() : foo(Bar::foos[0]) {}
    void setFoo(int i) { foo = Bar::foos.at(i); }
private:
    Foo& foo;
};

int main() {
    return 0;
}

Istotna jest tu klasa Bar, która musi zawierać statyczny wektor obiektów Foo. Chodzi teraz o to, by kwalifikator const odnosił się jedynie do samego wektora, a nie elementów tzn. chodzi mi o to, żeby po statycznym zainicjalizowaniu tego wektora nie można było nic dodać ani nic usunąć. Ma on być niezmienny ze względu na ilość elementów, ale co się zrobi z nimi, to już inna bajka. Same obiekty Foo będzie można jak najbardziej modyfikować, a zatem chciałbym by możliwe było przypisanie jego elementów do nie-const-referencji.

Rozwiązania widzę trzy:

  1. usunąć const z wektora Bar::foos (ale to osłabia bezpieczeństwo bo będzie można usunąć wszystkie elementy);
  2. kombinować z const_cast (nieporęczne bo trzeba będzie stosować to w wielu miejscach kodu);
  3. stworzyć dodatkową klasę MyThreeElemVector, która będzie zubożałym interfejsem do wektora, jedynie z metodą get(int i) (ale też nie bardzo - uważam to za przerost formy nad treścią).

Tylko, że trzy ww. rozwiązania wydają mi się takie trochę łopatologiczne.

Da się to jakoś ładnie zrobić? A jeśli tak to jak?

4

Problem polega na tym, że w wektorze zdefiniowanym jako const

const std::vector<int> data {1,2,3};

nie możesz zmieniać wartości. Są traktowane jako stałe.

data[0] = 3; // błąd kompilacji

Jeżeli chcesz mieć możliwość zmiany wartości elementów w **stałym **wektorze, możesz użyć std::reference_wrapper
Poniżej przykład kodu w C++17.

#include <iostream>
#include <vector>
#include <functional>

class Foo {
public:
    Foo( int i ) : i {i} {}
//private:
    int i;
};

class Bar
{
    inline static std::vector<Foo> foos_ { Foo {0}, Foo {1}, Foo {2} };
public:
    inline static const std::vector<std::reference_wrapper<Foo>> foos { Bar::foos_[0], Bar::foos_[1], Bar::foos_[2] };
};


class Qux {
public:
    Qux() : foo {Bar::foos[0]} {}
    void setFoo(int i) { foo = Bar::foos.at(i); }
//private:
    std::reference_wrapper<Foo> foo;
};

int main()
{
  Qux test;
  test.setFoo(2);
  std::cout << test.foo.get().i << std::endl;
  test.foo.get().i = 4;
  std::cout << test.foo.get().i << std::endl;
}
0

możesz też alokować wartości na stercie

https://onlinegdb.com/SkYbimdfw

#include <vector>
#include<memory>
#include<iostream>
class Foo {
public:
    Foo(int i) : i(i) {}
    using Ptr = std::shared_ptr<Foo>;
//private:
    int i;
};

class Bar {
public:
    inline static const std::vector<Foo::Ptr> foos{ std::make_shared<Foo>(1), std::make_shared<Foo>(2), std::make_shared<Foo>(3)};
};





int main() {
    Bar b;
    for(auto x : b.foos) {
        std::cout<< x->i << std::endl;
        x->i += 1;
    }
    std::cout << "changed" << std::endl;
    
    for(auto x : b.foos) {
      std::cout<< x->i << std::endl;
    }
    
    // b.foos.push_back(std::make_shared<Foo>(12));   // compile error
    
    
    return 0;
}

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