I'm using C++14 with protobuf to code.
In my proto file, I designed a nested message as below:
message Object {
// something
};
message Response {
repeated Object list = 1;
};
In my C++ project, I try to insert an element:
Object obj;
Response res;
// res.mutable_list()->Add(obj); // ERROR!
res.mutable_list()->Add()->CopyFrom(obj);
I really don't why but Add(obj) will cause a compile error:
cannot bind 'Object' lvalue to 'Object&&'
res.mutable_info()->Add(obj);
I really couldn't understand why because in the header file, I did find the definitions of the funcitons inline void RepeatedPtrField<Element>::Add(Element&& value) and inline void RepeatedPtrField<Element>::Add(const Element& value). But both res.mutable_list()->Add(std::move(obj)); and res.mutable_list()->Add(obj); will cause some compile errors. Another error is as below, which I totally can't understand what it is:
no matching function for call to 'google::protobuf::RepeatedPtrField::TypeHandler::New(Google::protobuf::Area*&, std::remove_reference<Object&>::type)' TypeHandler::New(arena_, std::move(value));
res.mutable_list()->Add()->CopyFrom(obj); works but why can't I simply call Add(obj)?
Add(Object &&object) function requires object argument to be rvalue reference. You can cast to rvalue reference with std::move.
Object obj;
Response res;
res.mutable_list()->Add(std::move(obj)); // This should work.
However after using std::move, you can not access to obj variable anymore, if you try to acces it you will be greeted with segmentation fault. This is why with protobuf, it is much better to create your child message objects from your parent object.
Related
This is my first experience with downcasting in C++ and I just can't understand the problem.
AInstruction and CInstruction inherit from AssemblerInstruction.
Parser takes the info in its ctor and creates one of those derived instruction types for its mInstruction member (accessed by getInstruction). In the program, a method of the base AssemblerInstruction class is used, for happy polymorphism.
But when I want to test that the Parser has created the correct instruction, I need to query the derived instruction members, which means I need to downcast parser.getInstruction() to an AInstruction or CInstruction.
As far as I can tell this needs to be done using a bunch of pointers and references. This is how I can get the code to compile:
TEST(ParserA, parsesBuiltInConstants)
{
AssemblerInstruction inst = Parser("#R3", 0).getInstruction();
EXPECT_EQ(inst.getInstructionType(), AssemblerInstruction::InstructionType::A);
AssemblerInstruction* i = &(inst);
AInstruction* a = dynamic_cast<AInstruction*>(i);
EXPECT_EQ(a->getLine(), "R3");
}
Running this gives this error:
unknown file: error: SEH exception with code 0xc0000005 thrown in the test body.
And stepping through the code, when the debugger is on the final line of the function, a is pointing to
0x00000000 <NULL>.
I imagine this is an instance where I don't have a full enough understanding of C++, meaning that I could be making a n00b mistake. Or maybe it's some bigger crazy problem. Help?
Update
I've been able to make this work by making mInstruction into a (dumb) pointer:
// in parser, when parsing
mInstructionPtr = new AInstruction(assemblyCode.substr(1), lineNumber);
// elsewhere in AssemblerInstruction.cpp
AssemblerInstruction* AssemblyParser::getInstructionPtr() { return mInstructionPtr; }
TEST(ParserA, parsesBuiltInConstants)
{
auto ptr = Parser("#R3", 0).getInstructionPtr();
AInstruction* a = dynamic_cast<AInstruction*>(ptr);
EXPECT_EQ(a->getLine(), "R3");
}
However I have trouble implementing it with a unique_ptr:
(I'm aware that mInstruction (non-pointer) is redundant, as are two types of pointers. I'll get rid of it later when I clean all this up)
class AssemblyParser
{
public:
AssemblyParser(std::string assemblyCode, unsigned int lineNumber);
AssemblerInstruction getInstruction();
std::unique_ptr<AssemblerInstruction> getUniqueInstructionPtr();
AssemblerInstruction* getInstructionPtr();
private:
AssemblerInstruction mInstruction;
std::unique_ptr<AssemblerInstruction> mUniqueInstructionPtr;
AssemblerInstruction* mInstructionPtr;
};
// in AssemblyParser.cpp
// in parser as in example above. this works fine.
mUniqueInstructionPtr = make_unique<AInstruction>(assemblyCode.substr(1), lineNumber);
// this doesn't compile!!!
unique_ptr<AssemblerInstruction> AssemblyParser::getUniqueInstructionPtr()
{
return mUniqueInstructionPtr;
}
In getUniqueInstructionPtr, there is a squiggle under mUniqueInstructionPtr with this error:
'std::unique_ptr<AssemblerInstruction,std::default_delete>::unique_ptr(const std::unique_ptr<AssemblerInstruction,std::default_delete> &)': attempting to reference a deleted function
What!? I haven't declared any functions as deleted or defaulted!
You can not downcast an object to something which doesn't match it's dynamic type. In your code,
AssemblerInstruction inst = Parser("#R3", 0).getInstruction();
inst has a fixed type, which is AssemblerInstruction. Downcasting it to AInstruction leads to undefined behavior - manifested as crash - because that is not what it is.
If you want your getInstruction to return a dynamically-typed object, it has to return a [smart] pointer to base class, while constructing an object of derived class. Something like that (pseudo code):
std::unique_ptr<AssemblerInstruction> getInstruction(...) {
return std::make_unique<AInstruction>(...);
}
Also, if you see yourself in need of downcasting object based on a value of a class, you are doing something wrong, as you are trying to home-brew polymorphism. Most of the times it does indicate a design flaw, and should instead be done using built-in C++ polymorphic support - namely, virtual functions.
I have an assignment where i was given c++ code that has multiple test functions, and i have to write the stri class with all the functions necesary for these tests to pass. I am having difficulty with one particular test about chain linking.
void Lab4Tests::testChainedSet() {
stri greet = "Hello";
assert(0==strcmp("Hello", greet.get()), "testChainedSet", "internal representation error");
greet.set("Hi").set("Buna");
assert(0==strcmp("Buna", greet.get()), "testChainedSet", "set failed");
}
My function inside the class that I wrote to solve this test is the following
char* set(const char* s){
len=strlen(s);
repres=new char(len+1);
strcpy(repres,s);
return repres;
}
I get an error when compiling the code
error: request for member 'set' in 'greet.stri::set(((const char*)"Hi"))', which is of non-class type 'char*'|
I dont understand chain linking that well, I would appreciate if somebody could point out what I'm doing wrong. Thanks in advance!
If you want to be able to chain calls you need to return a reference to the this object.
For instance
stri& set(const char* s)
{
repres = std::strdup(s);
return *this;
}
I've taken the liberty of simplifying your string duplication. I haven't fixed the memory leak that you will get if you call set when repres already contains dynamically allocated memory.
As a continuation of a: Thread, I came across a problem with
writing a method of a class which returns:
std::vector<std::unique_ptr<Object>>
I get compiler errors when such a return type is written. There is some problem with delete operand or something ...
Generally, I've wanted to write a method which initializes vector and returns it.
Could anyone help me how to write it?
EDIT:
I Get:
attempting to reference a deleted function h:\pliki programów (x86)\microsoft visual studio 12.0\vc\include\xmemory0
Here I have the following code snippet. Can I create such a method like this?
std::vector<std::unique_ptr<Object>> Class::TestMethod(int param)
{
std::vector<std::unique_ptr<Object>> array;
auto day = std::make_unique<Object>();
array.push_back(day);
return array;
}
Your error is actually coming from:
array.push_back(day);
This tries to put a copy of day in the vector, which is not permitted since it is unique.
Instead you could write array.push_back( std::move(day) ); however the following would be better, replacing auto day...:
array.emplace_back();
The copy constructor of std::unique_ptr is deleted. That causes a problem in the line:
array.push_back(day);
Use
array.push_back(std::move(day));
I'm writing macros for debugging system
I have an overloaded chained operator <<(MessageAssembler& target,message_type msg)
(message_type) is a template parameter for the operator
It adds msg to target's inner variable of type QTextStream.
The operator +=(MessageAssembler& result) of MessageAssembler passes result's stream to function which processes it based on parameters of result.
I want to do something like this:
#define FATAL(facility) NLog::assembler+=MessageAssembler(Log::fatal_sev,facility)<< __FILE__<<":"<<__LINE__
(NLog::assembler is a static variable of type MessageAssembler)
It should determine output's facility, allow a user to add its own message to output by using
FATAL(some_facility)<<"custom message"<<ObjectWhichCanBePassedToQTextStream()<<AnotherObject();
But MessageAssembler(Log::fatal_sev,facility) produces a reference to temporary error.
This
MessageAssembler& MessageAssembler::get_instance(Log::Severity _msg_sev,Log::Facility _msg_fac)
{
MessageAssembler tmp(_msg_sev,_msg_fac);
return tmp;
}
will return a reference to a non-existing object;
This
MessageAssembler& MessageAssembler::get_instance(Log::Severity _msg_sev,Log::Facility _msg_fac)
{
return new MessageAssembler tmp(_msg_sev,_msg_fac);
}
will cause a memory leak
This
QScopedPointer<MessageAssembler> MessageAssembler::get_instance(Log::Severity _msg_sev,Log::Facility _msg_fac)
{
return QScopedPointer<MessageAssembler>(new MessageAssembler tmp(_msg_sev,_msg_fac));
}
will not work because QScopedPointer can't be passed by value
I'm not sure if storing second static variable MessageAssembler chain_starter; is thread-safe.
I have not only FATAL macro, so the program won't be always terminated after the call.
How can i return a reference to a new MessageAssembler?
EDIT: My problem was solved by installing a third-party library for smart pointer, namely, yasper. The general solution is proposed by πάντα ῥεῖ.
The most concise answer is:
Don't do it using raw pointers! Use the c++ smart pointer features instead.
The most straightforward implementation seems to be, creating a std::unique_ptr<MessageAssembler> instance and return this one. The calling client will receive ownership of the created instance and it will be deleted automatically, as soon that reference goes out of scope.
I have a class TypeData and want to store objects of that type in a QMap then I want to get a specific object out of the map and call a memberfunction of this object.
But when I try to do that i get the following error message:
error C2662: 'TypeData::write': cannot convert 'this' pointer from 'const TypeData' to 'TypeData &'
here are the relevant code snippets:
QMap<QString, TypeData> typeDataList;
typeDataList.insert(currentID, temp);
typeDataList.value(currentID).write();
Can anyone tell what I', doing wrong here? And how I could fix this?
QMap::value returns a const T, i.e. a both a copy of the element in the map, and a non-modifyable one. Your write() method is probably not const, thus calling write() on the const T is not allowed. If value returned just T, it would work, but any changes write() does to the temporary object would be lost right away. (As the copy is destroyed right after).
So you can either make write() const if it doesn't modify the TypeData.
That's preferable, if possible.
Alternatively you can do:
typeDataList[currentID].write() // modifies the object in the map but also will insert a TypeData() if there is no entry for key currentID yet.
or, more verbose but without inserting a new element if none is found:
QMap<QString,TypeData>::Iterator it = typeDataList.find(currentID);
if ( it != typeDataList.constEnd() ) {
it->write();
} else {
// no typedata found for currentID
}