Coding Memo

[FlatBuffers] nested 에러 (nested was true) 본문

Language/C++

[FlatBuffers] nested 에러 (nested was true)

minttea25 2024. 3. 11. 13:40

Error

 

Create~~를 이용해 flatbuffer관련 객체나 구조체를 생성할 때 나타나는 에러이다.

assert에 의한 에러이다.

 


Problem

 

다음은 문제의 코드이다. CreateString을 이용해 flatbuffer 문자열을 만드는 중에 에러가 발생했다.

#pragma comment(lib, "Release\\flatbuffers.lib")

#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/util.h"

#include "flatbuffers_scehmas/MyGame_generated.h"

#include <iostream>

using namespace std;
using namespace MyGame;

int main()
{
    // error codes
    {
        flatbuffers::FlatBufferBuilder builder;

        Vec3 pos(0, 0, 0);

        // same as CreateMonster()
        MonsterBuilder mb(builder);

        auto name = builder.CreateString("Skeleton"); // error here

        mb.add_hp(2000);
        mb.add_name(name);
        mb.add_pos(&pos);
        auto monster = mb.Finish();

        builder.Finish(monster);

        // deserialize
        auto buf = builder.GetBufferPointer();
        auto data = MyGame::GetMonster(buf);

        cout << data->hp() << endl;
        cout << data->name()->str() << endl;
    }

    return 0;
}

Solution

 `Create`를 이용한 flatbuffer 구조체 생성 시(직렬화 시) 중에 `CreateString`을 호출하지 말고 그 전에 호출하여 가지고 있자.

 

int main()
{
    // error codes
    {
        flatbuffers::FlatBufferBuilder builder;

		// CreateMonster() 전에 호출
        auto name = builder.CreateString("Skeleton");

        Vec3 pos(0, 0, 0);

        // same as CreateMonster()
        MonsterBuilder mb(builder); // 이후 builder.nested = true

        mb.add_hp(2000);
        mb.add_name(name);
        mb.add_pos(&pos);
        auto monster = mb.Finish(); // 이후 builder.nested = false
        
        
        // 아니면 아래와 같이 처음부터 호출해도 OK
        // 순서상 CreateString이 먼저 호출되니까...!
        // auto monster = CreateMonster(builder, &pos, 100, 1000, builder.CreateString("Skeleton"));
        
        builder.Finish(monster);

        // deserialize
        auto buf = builder.GetBufferPointer();
        auto data = MyGame::GetMonster(buf);

        cout << data->hp() << endl;
        cout << data->name()->str() << endl;
    }

    return 0;
}

 


`Create`를 이용한 flatbuffer 구조체 생성 시(직렬화 시) 중에는 Finish 전까지 다른 구조체나 벡터를 생성하면 안된다.

 

 

flatbuffer 구조체를 Create하고 있을 때에는 `flatbuffers::FlatBufferBuilder`의 nested 값이 true가 된다. 이 상태에서는 특정 버퍼 위치에 해당 구조체를 직렬화하고 있는 상태이기 때문에 이 빌더를 이용하여 다른 값을 만들어서는 안된다.


nested 상태일 때, CreateString을 호출하면 내부적으로 다음이 순서대로 호출된다. (일부 생략)

/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const char pointer to the data to be stored as a string.
/// @param[in] len The number of bytes that should be stored from `str`.
/// @return Returns the offset in the buffer where the string starts.
void CreateStringImpl(const char *str, size_t len) {
  NotNested();
  PreAlign<uoffset_t>(len + 1);  // Always 0-terminated.
  buf_.fill(1);
  PushBytes(reinterpret_cast<const uint8_t *>(str), len);
  PushElement(static_cast<uoffset_t>(len));
}

 

NotNested()

void NotNested() {
  // If you hit this, you're trying to construct a Table/Vector/String
  // during the construction of its parent table (between the MyTableBuilder
  // and table.Finish().
  // Move the creation of these sub-objects to above the MyTableBuilder to
  // not get this assert.
  // Ignoring this assert may appear to work in simple cases, but the reason
  // it is here is that storing objects in-line may cause vtable offsets
  // to not fit anymore. It also leads to vtable duplication.
  FLATBUFFERS_ASSERT(!nested);
  // If you hit this, fields were added outside the scope of a table.
  FLATBUFFERS_ASSERT(!num_field_loc);
}

위에도 이유가 작성되어 있다. 

FLATBUFFERS_ASSERT(!nested) 부분에서 에러가 난다.

 

 

즉, `Create[flabuffer struct]`를 실행시키고 Finish가 되기 전까지 `CreateString()`등의 메서드를 호출하여 다른 벡터나 객체를 만들면 안된다.

'Language > C++' 카테고리의 다른 글

[메모] const 함수 유의사항 (C2665 에러 등)  (0) 2024.04.16
[Winsock] WSAEINVAL(10022) 에러 (ConnectEx)  (0) 2024.03.25
[C++] 가상 소멸자  (0) 2024.03.06
[C++] pack pragma (메모리 정렬)  (0) 2024.03.05
Use After Free  (0) 2023.11.02