First of all, thank you very much for taking the time to look at my question. Second, I have read this and my class does not have any virtual methods I am forgetting to include. I'll go over additional things I have tried after I describe my problem.
I am getting an undefined reference to `vtable for SubcomponentTypeWidget' error when I build my code using gcc version 3.4.6 20060404. Visual Studio 2005 has no issues. I love Linux, but my current political situation has delegated it to the red headed step child that regularly suffers abuse. Hopefully by our powers combined, I can remedy that.
I am using Qt version 4.6.2. I am using gcc 3.4.6 20060404 on Red Hat 4.
This is my header:
#ifndef SubcomponentTypeWidget_h
#define SubcomponentTypeWidget_h
#include <vector>
#include "ui_SubcomponentTypeWidget.h"
#include "Subcomponent.h"
class SubcomponentTypeWidget : public QWidget, public Ui::SubcomponentTypeWidget
{
Q_OBJECT
Q_PROPERTY(QString title READ title WRITE setTitle)
public:
SubcomponentTypeWidget(QWidget* parent,
Models::Subcomponent::SubcomponentType subcomponentType = Models::Subcomponent::kSolid)
: QWidget(parent),
m_subcomponentType(subcomponentType),
m_subcomponentTypeButtonGroup(new QButtonGroup(this))
{
this->initialize();
}
Models::Subcomponent::SubcomponentType subcomponentType() const { return m_subcomponentType; }
void setSubcomponentType(Models::Subcomponent::SubcomponentType type);
void setNonCompatibleTypes(const std::vector<Models::Subcomponent::SubcomponentType>& types);
QString title() const { return m_subcomponentGroupBox->title(); }
void setTitle(const QString &title) { m_subcomponentGroupBox->setTitle(title); }
signals:
void subcomponentTypeChanged();
protected slots:
void handleSubcomponentTypeChoice(int subcomponentTypeChoiceId);
protected:
void initialize();
Models::Subcomponent::SubcomponentType m_subcomponentType;
QButtonGroup* m_subcomponentTypeButtonGroup;
};
#endif // SubcomponentTypeWidget_h
The implementation is here:
#include "SubcomponentTypeWidget.h"
void SubcomponentTypeWidget::setSubcomponentType(Models::Subcomponent::SubcomponentType type)
{
if (type != m_subcomponentType)
{
m_subcomponentType = type;
emit subcomponentTypeChanged();
}
}
void SubcomponentTypeWidget::setNonCompatibleTypes(const std::vector<Models::Subcomponent::SubcomponentType>& types)
{
m_subcomponentTypeButtonGroup->button(static_cast<int>(Models::Subcomponent::kSolid) + 1)->setEnabled(true);
m_subcomponentTypeButtonGroup->button(static_cast<int>(Models::Subcomponent::kComplement) + 1)->setEnabled(true);
m_subcomponentTypeButtonGroup->button(static_cast<int>(Models::Subcomponent::kHole) + 1)->setEnabled(true);
for (std::vector<Models::Subcomponent::SubcomponentType>::const_iterator it = types.begin(); it != types.end(); ++it)
{
m_subcomponentTypeButtonGroup->button(static_cast<int>(*it) + 1)->setEnabled(false);
if (*it == m_subcomponentType)
m_subcomponentTypeButtonGroup->button(static_cast<int>(Models::Subcomponent::kSolid) + 1)->setChecked(true);
}
}
void SubcomponentTypeWidget::handleSubcomponentTypeChoice(int subcomponentTypeChoiceId)
{
if (static_cast<Models::Subcomponent::SubcomponentType>(subcomponentTypeChoiceId - 1) != m_subcomponentType)
{
m_subcomponentType = static_cast<Models::Subcomponent::SubcomponentType>(subcomponentTypeChoiceId - 1);
emit subcomponentTypeChanged();
}
}
void SubcomponentTypeWidget::initialize()
{
this->setupUi(this);
m_subcomponentTypeButtonGroup->addButton(m_solidRadioButton, static_cast<int>(Models::Subcomponent::kSolid) + 1);
m_subcomponentTypeButtonGroup->addButton(m_complementRadioButton, static_cast<int>(Models::Subcomponent::kComplement) + 1);
m_subcomponentTypeButtonGroup->addButton(m_holeRadioButton, static_cast<int>(Models::Subcomponent::kHole) + 1);
m_subcomponentTypeButtonGroup->button(static_cast<int>(m_subcomponentType) + 1)->setChecked(true);
connect(m_subcomponentTypeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(handleSubcomponentTypeChoice(int)));
}
The actual error messages I am receiving are:
../lib/libMeshAndGeometry.a(AddAdvancedDialog.o)(.gnu.linkonce.t._ZN20Ui_AddAdvancedDialog7setupUiEP7QDialog+0x955): In function `Ui_AddAdvancedDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddAdvancedDialog.o)(.gnu.linkonce.t._ZN20Ui_AddAdvancedDialog7setupUiEP7QDialog+0x960): In function `Ui_AddAdvancedDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddAdvancedDialog.o)(.gnu.linkonce.t._ZN20Ui_AddAdvancedDialog7setupUiEP7QDialog+0x99b): In function `Ui_AddAdvancedDialog::setupUi(QDialog*)':
: undefined reference to `SubcomponentTypeWidget::initialize()'
../lib/libMeshAndGeometry.a(AddBoxDialog.o)(.gnu.linkonce.t._ZN15Ui_AddBoxDialog7setupUiEP7QDialog+0xfe8): In function `Ui_AddBoxDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddBoxDialog.o)(.gnu.linkonce.t._ZN15Ui_AddBoxDialog7setupUiEP7QDialog+0xff3): In function `Ui_AddBoxDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddBoxDialog.o)(.gnu.linkonce.t._ZN15Ui_AddBoxDialog7setupUiEP7QDialog+0x102e): In function `Ui_AddBoxDialog::setupUi(QDialog*)':
: undefined reference to `SubcomponentTypeWidget::initialize()'
../lib/libMeshAndGeometry.a(AddConeDialog.o)(.gnu.linkonce.t._ZN16Ui_AddConeDialog7setupUiEP7QDialog+0x7ef): In function `Ui_AddConeDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddConeDialog.o)(.gnu.linkonce.t._ZN16Ui_AddConeDialog7setupUiEP7QDialog+0x7fa): In function `Ui_AddConeDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddConeDialog.o)(.gnu.linkonce.t._ZN16Ui_AddConeDialog7setupUiEP7QDialog+0x835): In function `Ui_AddConeDialog::setupUi(QDialog*)':
: undefined reference to `SubcomponentTypeWidget::initialize()'
../lib/libMeshAndGeometry.a(AddCylinderDialog.o)(.gnu.linkonce.t._ZN20Ui_AddCylinderDialog7setupUiEP7QDialog+0x9c4): In function `Ui_AddCylinderDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddCylinderDialog.o)(.gnu.linkonce.t._ZN20Ui_AddCylinderDialog7setupUiEP7QDialog+0x9cf): In function `Ui_AddCylinderDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddCylinderDialog.o)(.gnu.linkonce.t._ZN20Ui_AddCylinderDialog7setupUiEP7QDialog+0xa0a): In function `Ui_AddCylinderDialog::setupUi(QDialog*)':
All of my makefiles have been generated from my .pro file using qmake. The main make files, the main .pro file, and the widgets and MeshAndGeometry make and .pro files are attached here as an archive. One of the .ui files is attached here.
I have tried a number of things.
I am sure this is not a stale object file issue. I have built this from scratch and I still have the the problem.
I checked all of my capitalization issues. One of the problems I have noticed with doing most of this on Windows and then moving it to Linux is that people make mistakes with capitalization, and Windows doesn't care about capitalization.
I ran nm -a -C SubcomponentTypeWidget.o to see if the necessary vtable was there, and it wasn't. However, the 'missing' methods were there.
Creating a virtual destructor does not force vtable generation for SubcomponentTypeWidget.
I have tried removing large chunks of SubcomponentTypeWidget's functionality. This results in removing the specific linker error messages for methods, but it does not remove the undefined reference to vtable message. I have removed everything from SubcomponentTypeWidget other than the constructor, and in this case I still receive the "undefined reference to vtable" message, but without any mention to specific methods we are looking for.
Changing the order of which widgets and MeshingAndGeometry are linked in does not help.
I have tried gcc versions 3.4.6 20060404 and 4.1.2 20080704.
Help me, Obi-Wan Kenobi. You're my only hope.
Thank you all very, very much,
-Brian J. Stinar-
went through your codes the error most likely arises from the following statement:
=======================================================
void SubcomponentTypeWidget::initialize()
{
this->setupUi(this);
//rest of codes
}
=======================================================
you are sort of breaking the structure of Qt by making SubcomponentTypeWidget a subclass of Ui::SubcomponentTypeWidget. You are actually using yourself to setup a UI of yourself in this case. Coupled that with the fact that you are using multiple class inheritance, you are just confusing the compiler on which virtual method to refer to during runtime.
Instead of subclassing Ui::SubcomponentTypeWidget, just make it a private variable in SubcomponentTypeWidget
//SubcomponentTypeWidget.h
private:
Ui::SubcomponentTypeWidge ui;
implement the following in your init function and you should be good to go
void SubcomponentTypeWidget::initialize()
{
ui.setupUi(this);
//rest of codes
}
My problem was with solution point number six. I actually did NOT change this order correctly. I was changing the order in the INCPATH instead of the order in the LIBS.
After adding the line MeshAndGeometry.depends = widgets to my master.pro file, running qmake, and running make, this problem went away.
Thank everyone very much for their comments and help.
-Brian J. Stinar-
Related
This is for windows using MSVC compiler version 14.28.29910:
Libraries built using colcon. This was meant for a ROS2 application but I dont believe ROS has anything to do with it.
I have been stuck on this issue for two days now and I still am at a loss as to what is going on. Any help will be greatly appreciated.
I have a library that I am statically linking against. Library A. it is built with colcon. Could this be a linking issue or an issue with the fact that I build library A with a certain set of preprocessors and I build library B with a different set of preprocessors that change the Gameobject class to a different version shown below but same function implementations.
ament_auto_add_library(A STATIC
${SOURCES}
${HEADERS}
)
ament_target_dependencies(A ${ALL_DEPENDS})
install(TARGETS
A
EXPORT A_export
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
ament_export_libraries(A_export HAS_LIBRARY_TARGET)
I then link to it from a ros2 package using the standard
target_link_libraries(B A)
I have a object called Gameobject that is defined in library A.
#file --------------------------Gameobject.h
#ifdef InLibraryA
class Gameobject
{
int GetPosx(){return data.x;}
}
#else
class Gameobject
{
int GetPosx(){return data.x;}
}
#endif
#file --------------------------MoveGameObject.h
class MoveGameObject
{
int MoveGObj_inline(Gameobject* g)
{
return g->getPosx();
}
int MoveGObj(Gameobject* g);
}
#file --------------------------MoveGameObject.cpp
int MoveGameObject::MoveGObj(Gameobject* g)
{
return g->getPosx();
}
Now in library B , I do this within a subscription callback
SomeCallback()
{
Gameobject* g = GetGObjectFromPool();
MoveGameObject* m= new MoveGameObject();
//this will return NULL value
int posx = m->MoveGObj(g);
//this will be fine because it was inlined?
int possx = m->MoveGObj_inline(g);
}
You will see that I get null when calling the function that was NOT inlined for calling the getter function from Gameobject. I dont get null for the inlined function even though they run the exact same code. Note that this only happens to non-inline functions that call Gameobject functions. Does not happen to functions that do not read memory from Gameobject. addingTwoInts() for example works fine Non-inline. There are no errors. It is undefined behavior. Any ideas on what I could be doing wrong for this to happen? The simplified code above is the same as to what is happening in my code, just removed unnecessary details.
If I instantiate a lambda somewhere (and the compiler doesn't inline it), I can find a string showing where the lambda is located in my c++ code like this:
... ?AV<lambda_1>#?0??MyFunction#MyScopedClass#MyNamespace##SAXXZ# ...
I don't want this information in the executable, as it could give away important names of classes and functions.
All kinds of output debug information are turned off. If I use a normal function instead, the final executable doesn't have this information, so manually converting all lambdas into normal functions would "fix it". But what's the best way to handle this? Can we tell the compiler to transform lambdas into normal functions?
UPDATE: I tested with other compilers: g++ and clang. They both leave the same references. I also found another unanswered question about this Gcc - why are lambdas not stripped during release build Please don't come with the "why do you care about a few symbols anyway".
Here's some code you can test with:
#include <iostream>
#include <functional>
class MyUnscopedClass
{
public:
MyUnscopedClass(const std::function<void(int x)>& f) :
f(f)
{
}
std::function<void(int x)> f;
};
namespace MyNamespace
{
class MyScopedClass
{
public:
static void temp1(int x)
{
std::cout << x * (x + 1);
}
static void MyFunction()
{
//MyUnscopedClass obj(temp1); // no symbols
MyUnscopedClass obj([](int x) // ?AV<lambda_1>#?0??MyFunction#MyScopedClass#MyNamespace##SAXXZ#
{
std::cout << x;
});
obj.f(23);
}
};
}
int main()
{
MyNamespace::MyScopedClass::MyFunction();
}
With the help of #dxiv in the comments, I found the problematic setting.
Configuration Properties > General > C++ Language Standard
can't be, for some reason,
Preview - Features from the Latest C++ Working Draft (std:c++latest)
So I set it to the second most recent one
ISO C++17 Standard (std:c++17)
and I get a random identifier instead.
AV<lambda_f65614ace4683bbc78b79ad57f781b7f>##
I'm still curious how this identifier is chosen though.
I am just trying to compile a bit bigger project using the Visual Studio 2012 Release Candidate, C++. The project was/is compiled using the VS2010 now. (I am just greedy to get the C++11 things, so I tried. :)
Apart of things that I can explain by myself, the project uses the code like this:
ostringstream ostr;
ostr << "The " __FUNCTION__ "() failed to malloc(" << i << ").";
throw bad_alloc(ostr.str().c_str());
The compiler now complains
error C2248: 'std::bad_alloc::bad_alloc' : cannot access private member declared
in class 'std::bad_alloc'
... which is true. That version of constructor is now private.
What was the reason to make that version of constructor private? Is it recommended by C++11 standard not to use that constructor with the argument?
(I can imagine that if allocation failed, it may cause more problems to try to construct anything new. However, it is only my guess.)
Thanks,
Petr
The C++11 Standard defines bad_alloc as such (18.6.2.1):
class bad_alloc : public exception {
public:
bad_alloc() noexcept;
bad_alloc(const bad_alloc&) noexcept;
bad_alloc& operator=(const bad_alloc&) noexcept;
virtual const char* what() const noexcept;
};
With no constructor that takes a string. A vendor providing such a constructor would make the code using it not portable, as other vendors are not obliged to provide it.
The C++03 standard defines a similar set of constructors, so VS didn't follow this part of the standard even before C++11. MS does try to make VS as standard compliant as possible, so they've probably just used the occasion (new VS, new standard) to fix an incompatibility.
Edit: Now that I've seen VS2012's code, it is also clear why the mentioned constructor is left private, instead of being completely removed: there seems to be only one use of that constructor, in the bad_array_new_length class. So bad_array_new_length is declared a friend in bad_alloc, and can therefore use that private constructor. This dependency could have been avoided if bad_array_new_length just stored the message in the pointer used by what(), but it's not a lot of code anyway.
If you are accustomed to passing a message when you throw a std::bad_alloc, a suitable technique is to define an internal class that derives from std::bad_alloc, and override ‘what’ to supply the appropriate message.
You can make the class public and call the assignment constructor directly, or make a helper function, such as throw_bad_alloc, which takes the parameters (and additional scalar information) and stores them in the internal class.
The message is not formatted until ‘what’ is called. In this way, stack unwinding may have freed some memory so the message can be formatted with the actual reason (memory exhaustion, bad request size, heap corruption, etc.) at the catch site. If formatting fails, simply assign and return a static message.
Trimmed example:
(Tip: The copy constructor can just assign _Message to nullptr, rather than copy the message since the message is formatted on demand. The move constructor, of course can just confiscate it :-).
class internal_bad_alloc: public std::bad_alloc
{
public:
// Default, copy and move constructors....
// Assignment constructor...
explicit internal_bad_alloc(int errno, size_t size, etc...) noexcept:
std::bad_alloc()
{
// Assign data members...
}
virtual ~internal_bad_alloc(void) noexcept
{
// Free _Message data member (if allocated).
}
// Override to format and return the reason:
virtual const char* what(void) const noexcept
{
if (_Message == nullptr)
{
// Format and assign _Message. Assign the default if the
// format fails...
}
return _Message;
}
private:
// Additional scalar data (error code, size, etc.) pass into the
// constructor and used when the message is formatted by 'what'...
mutable char* _Message;
static char _Default[];
}
};
//
// Throw helper(s)...
//
extern void throw_bad_alloc(int errno, size_t size, etc...)
{
throw internal_bad_alloc(errno, size, etc...);
}
I've been using Crypto++ with VS2005 and VS2010 for a while now. But recently I needed to use it with and application directly. The same code compiles fine when I'm compiling as a DLL and does not compile when compiling as an application.
This is the smallest sample that reproduces the error is this (based on cryptopp561\algparam.h:301 CryptoPP::AlgorithmParametersTemplate
class Base
{
protected:
virtual void MoveInto(void *p) const = 0;
};
template<class T>
class Test: public Base
{
public:
void MoveInto(void * buffer) const
{
Test<T> *x = new(buffer) Test<T>(*this);
}
};
extern template class Test<bool>;
The compilation parameters are the same, only difference that I saw was the configuration type in the project ("Application (.exe)" generates the error and "Dynamic Library (.dll)" does not).
This is the compiler error:
main.h(15): error C2061: syntax error : identifier 'buffer'
main.h(14) : while compiling class template member function 'void Test<T>::MoveInto(void *) const'
with
[
T=bool
]
main.h(20) : see reference to class template instantiation 'Test<T>' being compiled
with
[
T=bool
]
It seems to occur only when theres inheritance. Ommiting : public Base in the class Test declaration makes the error go away.
EDIT:
The problem was in a header included somewhere that defined a a debug version for operator new but didn't declared the placement new version.
Did you #include <new>, the header file that declares placement-new?
Funnily, extern templates are to tell the compiler to not instantiante at some point, so the second error does not make sense to me. Are you certain your compiler has support for extern templates? What if you do the opposite, explicit instantiation:
template class Test<bool>;
VERSION 1
class Doh {
private:
static std::map<const std::string, const Doh*> someMap;
std::string stringValue_;
public:
Doh(std::string str) : stringValue_(str) {
Doh::someMap.insert(
std::make_pair<const std::string,const Doh*>
(this->stringValue_,this)
);
}
}
The above was ok with MSVC 2010 but with MSVC 2008 it fails – and I guess it is because the object is not constructed yet when it is inserted in the map (I got a memory access violation).
So, I tried a delayed insertion, which worked:
VERSION 2
Doh(std::string str) : stringValue_(str) {
boost::thread(&Doh::insertIntoTheStaticMap,this);
}
void insertIntoTheStaticMap() {
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
Doh::someMap.insert(
std::make_pair<const std::string,const Doh*>
(this->stringValue_,this)
);
}
But as you might be able to guess, my intention is to have the static Doh::someMap as a common lookup dictionary.
VERSION 1 didn’t need any thread-safety because I would create all Doh instances in the same thread – in initialization blocks - which would be called by dynamic initializers before I enter main().
But with VERSION 2, the naïve sleep() is neither graceful nor reliable (not to mention, I might need to lock the map before insertion).
What would be a nice KISS approach?
Only potential issue I see is the initialization of the static member, if there are multiple source files. Try guarding it with a function.
class Doh {
private:
static std::map< std::string, Doh * > &get_map() {
static std::map< std::string, Doh * > someMap;
return someMap; // initialize upon first use
}
std::string stringValue_;
public:
Doh(std::string str) : stringValue_(str) {
get_map().insert(
std::make_pair
(this->stringValue_,this)
);
}
};
In neither version is there any sign of init for stringvalue_ - what does the debugger show you about this key when you hit the map insert in version 1 of the code? How is this field set up, and what is its type?
Running this in the debugger for VS2008 should allow you to narrow down the point of failure into the <map> source, I would have thought.