Meu objetivo é serializar informações usando protobuf em C++.
arquivo proto:
syntax = "proto3";
package PhoneBookSerialize;
message Date {
int32 year = 1;
int32 month = 2;
int32 day = 3;
}
message Contact {
string name = 1;
Date birthday = 2;
repeated string phone_number = 3;
}
message ContactList{
repeated Contact contact = 1;
}
Código relacionado ao contato:
struct Contact {
std::string name;
std::optional<Date> birthday;
std::vector<std::string> phones;
bool operator<(const Contact& other) const {
return name < other.name;
}
};
class PhoneBook {
public:
explicit PhoneBook(std::vector<Contact> contacts);
void SaveTo(std::ostream& output) const;
private:
std::vector<Contact> contact_book;
};
PhoneBook::PhoneBook(std::vector<Contact> contacts) : contact_book(contacts) {
std::sort(contact_book.begin(), contact_book.end());
};
Função de serialização:
void PhoneBook::SaveTo(std::ostream& output) const {
PhoneBookSerialize::ContactList contact_list;
for(const auto& contact : contact_book){
PhoneBookSerialize::Contact* pb_contact = contact_list.add_contact();
pb_contact->set_name(contact.name);
if(contact.birthday.has_value()){
PhoneBookSerialize::Date* pb_date = pb_contact->mutable_birthday();
pb_date->set_year(contact.birthday->year);
pb_date->set_month(contact.birthday->month);
pb_date->set_day(contact.birthday->day);
}
for(const auto& phone : contact.phones){
pb_contact->add_phone_number(phone);
}
}
contact_list.SerializeToOstream(&output);
};
arquivo main.cpp
#include "phone_book.h"
#include "contact.pb.h"
#include <sstream>
using namespace std;
int main(){
const PhoneBook ab({
{"Ab ba", Date{1980, 1, 13}, {"+79850685521"}},
{"Ac ca", Date{1989, 4, 23}, {"+79998887766", "+71112223344"}},
{"Ad da", Date{1989, 4, 23}, {}},
{"No Birthday", std::nullopt, {"+7-4862-77-25-64"}},
});
ostringstream output(std::ios::binary);
ab.SaveTo(output);
istringstream input(output.str(), std::ios::binary);
PhoneBookSerialize::ContactList list;
list.ParseFromIstream(&input);
return 0;
}
Arquivo CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(PhoneBookProtobuf LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find Protocol Buffers package
find_package(Protobuf REQUIRED)
# Find Abseil package
find_package(absl REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Generate protobuf files from proto directory
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS proto/contact.proto)
# Add all source files
add_executable(main
src/main.cpp
src/phone_book.cpp
src/phone_book.h
${PROTO_SRCS}
${PROTO_HDRS}
)
# Link necessary libraries
target_link_libraries(main
${Protobuf_LIBRARIES}
absl::log
absl::log_internal_message
absl::log_internal_check_op
)
Estou usando os seguintes comandos para criar e executar meu código:
1. Configure project:
cmake --preset default
2. Build Project:
cmake --build --preset debug
3. Run Project:
./build/main
Depois de executar o projeto, estou recebendo uma falha de segmentação no list.ParseFromIstream(&input);
. Suponho que tenha algo a ver com o meu arquivo de configuração do Cmake. Também adicionei o pacote abseil à minha configuração do Cmake, porque sem ele no meu sistema operacional (macOS), o código não compila.
Mensagens de erro:
AddressSanitizer:DEADLYSIGNAL
=================================================================
==4319==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000020 (pc 0x000000000020 bp 0x7ff7b0d5f350 sp 0x7ff7b0d5f318 T0)
==4319==Hint: pc points to the zero page.
==4319==The signal is caused by a READ memory access.
==4319==Hint: address points to the zero page.
#0 0x000000000020 (<unknown module>)
#1 0x00010f5e6a24 in google::protobuf::internal::TcParser::FastMtR1(google::protobuf::MessageLite*, char const*, google::protobuf::internal::ParseContext*, google::protobuf::internal::TcFieldData, google::protobuf::internal::TcParseTableBase const*, unsigned long long)+0x74 (libprotobuf.29.3.0.dylib:x86_64+0xb8a24)
#2 0x00010f63abdb in bool google::protobuf::internal::MergeFromImpl<false>(google::protobuf::io::ZeroCopyInputStream*, google::protobuf::MessageLite*, google::protobuf::internal::TcParseTableBase const*, google::protobuf::MessageLite::ParseFlags)+0xd1 (libprotobuf.29.3.0.dylib:x86_64+0x10cbdb)
#3 0x00010f63bda2 in google::protobuf::MessageLite::ParseFromIstream(std::__1::basic_istream<char, std::__1::char_traits<char>>*)+0x32 (libprotobuf.29.3.0.dylib:x86_64+0x10dda2)
#4 0x00010f1adbf9 in main main.cpp:23
#5 0x7ff8165ad52f in start+0xbef (dyld:x86_64+0xfffffffffff1f52f)
==4319==Register values:
rax = 0x0000606000001700 rbx = 0x00007ff7b0d5fb20 rcx = 0x0000000000000020 rdx = 0x0000000000000000
rdi = 0x000000010f220840 rsi = 0x0000606000001700 rbp = 0x00007ff7b0d5f350 rsp = 0x00007ff7b0d5f318
r8 = 0xffffffffffffffff r9 = 0x0000000000000000 r10 = 0x00007fffffffff01 r11 = 0x00007fffffffff01
r12 = 0x000000010f222480 r13 = 0x00007ff7b0d5f3e8 r14 = 0x0000000000000000 r15 = 0x0000000000000000
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (<unknown module>)
==4319==ABORTING
zsh: abort ./build/main