Заобикаляне на постоянните елементи на контейнера Boost Multi-Index

Имам някакъв клас данни, който е скъп за копиране, но трябва да бъде променлив, тъй като често се актуализира според събитията. Имам нужда и от мултииндексен контейнер, за да държа много такива класове. Опитвам се да го настроя с помощта на boost::multi_index. Например:

struct MutableAndExpensiveToCopy {
    int some_value;
    std::map<int, std::string> some_huge_map;
    std::map<int, std::string> an_even_bigger_map;
}

struct CanBeMultiIndexed
{
    // "Payload" - its fields will never be used as indices
    MutableAndExpensiveToCopy data;

    // Indexes        
    int         id;
    std::string label;
}

typedef multi_index_container<
    CanBeMultiIndexed,
    indexed_by<
        ordered_unique<member<CanBeMultiIndexed, int, &CanBeMultiIndexed::id>>,
        ordered_non_unique<member<CanBeMultiIndexed,std::string,&CanBeMultiIndexed::label>>
    > 
> MyDataContainer;

Проблемът ми е, че multi_index третира елементите в контейнера като константи (за да се запази целостта на всички индекси). Например, следното няма да се компилира:

void main() {
    // put some data in the container
    MyDataContainer container;
    CanBeMultiIndexed e1(1, "one"); // conto'r not shown in class definition for brevity
    CanBeMultiIndexed e2(2, "two");

    container.insert(e1);
    container.insert(e2);

    // try to modify data
    MyDataContainer::nth_index<1>::type::iterator iter = container.get<1>().find(1);
    iter->data.some_value = 5;  // constness violation
}

Не мога да използвам метода replace(), тъй като е скъпо да копирам класа на полезния товар. Запознат съм с метода modify(), но използването му изглежда тромаво, тъй като в моята реална програма класът "полезен товар" може да съдържа множество полета и писането на функтор за всяко едно е изключено.

Някакви предположения?

РЕДАКТИРАНЕ: След известно заиграване се опитах да заменя елемента с данни с shared_ptr на MutableAndExpensiveToCopy:

struct CanBeMultiIndexed
{
    // "Payload" - its fields will never be used as indices
    boost::shared_ptr<MutableAndExpensiveToCopy> data;

    // Indexes        
    int         id;
    std::string label;
}

Това проработи и успях да компилирам своя main(), включително кода за промяна на данните:

void main() {
    ...
    iter->data->some_value = 5;  // this works
    ...
}

Това до голяма степен ми дава това, което исках, но не съм сигурен защо работи, така че:

  1. Този код прави ли това, което възнамерявах, или има някакво предупреждение, което пропускам?
  2. Как така работи това? Постоянността на shared_ptr не се отнася ли за неговия -> оператор?

person bavaza    schedule 03.04.2011    source източник


Отговори (1)


На първо място, ImMutableAndExpensiveToCopy изглежда точно обратното --mutable, тъй като се опитвате да промените съдържанието му в примера. Опитайте просто това:

struct CanBeMultiIndexed
{
    mutable ImMutableAndExpensiveToCopy data;
    int         id;
    std::string label;
}

(и евентуално променете името ImMutableAndExpensiveToCopy за последователност.)

person Joaquín M López Muñoz    schedule 03.04.2011
comment
@Joaquin - с ImMutableAndExpensiveToCopy исках да кажа, че съм променлив и скъп за копиране. Ще поправя примера, за да стане ясно. - person bavaza; 03.04.2011
comment
Добре, сега го разбрах :-) Както и да е, mutable- квалифицирането решава ли проблема ти? - person Joaquín M López Muñoz; 03.04.2011
comment
@Хоакин - не. Както е посочено в документацията, итераторът се е върнал от, напр. find() по дефиниция е const. Това е с цел да се гарантира целостта на индекса. BTW, AFAIK, членовете на клас/структура са променливи по подразбиране, така че квалификаторът mutable е излишен. - person bavaza; 07.04.2011
comment
@bavaza: Сигурен съм, че Хоакин знае, че итераторите са постоянни, тъй като той е автор на библиотеката Boost.MultiIndex. Опитахте ли предложението му или просто решихте, че няма да работи? Изглежда мислите, че mutable е обратното на const, което не е така. Членовете не са променливи по подразбиране. - person interjay; 13.04.2011
comment
@Juaquin, Interjay: Опитах mutable и проблемът е решен. Благодаря. - person bavaza; 14.04.2011
comment

Работя с OpenGL ES 2.0 и се опитвам да изградя моя обектен клас с някои методи за завъртане/превеждане/мащабиране.

Просто настройвам обекта си в 0,0,0 и след това го премествам на желаната позиция на екрана. По-долу са моите методи за отделно преместване. След това стартирам buildObjectModelMatrix, за да предам всички матрици в един objectMatrix, така че мога да взема върховете и да ги умножа с моя modelMatrix/objectMatrix и да го изобразя след това.

Това, което смятам за правилно, трябва да умножа матриците си в този ред:

[мащаб]x[въртене]x[превод]

->

[temp]x[превод]

->

[objectMatrix]

Намерих малко литература. Може би ще го получа след няколко минути, ако искам, ще го актуализирам.

Начало на Android 3D

https://gamedev.stackexchange.com/questions/16719/what-is-the-correct-order-to-multiply-scale-rotation-and-translation-matrices-f

  setIdentityM(scaleMatrix, 0);
  setIdentityM(translateMatrix, 0);
  setIdentityM(rotateMatrix, 0);
public void translate(float x, float y, float z) {
    translateM(translateMatrix, 0, x, y, z);
    buildObjectModelMatrix();
}

public void rotate(float angle, float x, float y, float z) {
    rotateM(rotateMatrix, 0, angle, x, y, z);
    buildObjectModelMatrix();
}

public void scale(float x, float y,float z) {
    scaleM(scaleMatrix, 0, x, y, z);
    buildObjectModelMatrix();
}

private void buildObjectModelMatrix() {
    multiplyMM(tempM, 0, scaleMatrix, 0, rotateMatrix, 0);
    multiplyMM(objectMatrix, 0, tempM, 0, translateMatrix, 0);
}

РЕШЕНО: Проблемът в цялата работа е, че ако мащабирате преди да преведете, получавате разлика в разстоянието, което превеждате! правилният код за умножаване на вашите матрици трябва да бъде (поправете ме, ако греша)

    private void buildObjectModelMatrix() {
    multiplyMM(tempM, 0, translateMatrix, 0, rotateMatrix, 0);
    multiplyMM(objectMatrix, 0, tempM, 0, scaleMatrix, 0);
}

с това първо превеждате и завъртате. След това можете да мащабирате обекта.

Тествано с множество обекти... така че се надявам това да е помогнало :)

- person Gabriel; 26.07.2013
comment
@bavaza членовете на клас/структура са променливи по подразбиране - това е неправилно. Членовете на клас/структура са неконстантни по подразбиране, но не могат да се променят. - person quant; 09.02.2015