Just ran into these 2 Clang errors:
ld.lld: error: undefined symbol: vtable for HashFn
>>> referenced by hashFn.h:40 ......
HashFn::HashFn(int, bool)
And
ld.lld: error: undefined symbol: vtable for HashFn
>>> referenced by hashFn.h:36 ......
HashFn::HashFn(HashFn const&)
hashFn.h -->
#ifndef HASHFN_H_
#define HASHFN_H_
#include "./base.h"
typedef uint64_t uint64Array[30];
static int precomputedArraySize = sizeof(uint64Array) / sizeof(uint64_t);
inline uint64_t customPow(uint64Array *precomputedPowers, bool usePrecomputed,
uint64_t base, int exp) {
if (usePrecomputed && exp < precomputedArraySize) {
return (*precomputedPowers)[exp];
}
// TOOD: Optimization possible here when passed in toSize which is bigger
// than precomputedArraySize, we can start from the value of the last
// precomputed value.
uint64_t result = 1;
while (exp) {
if (exp & 1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
// Functor for a hashing function
// Implements a Rabin fingerprint hash function
class HashFn {
public:
// Initialize a HashFn with the prime p which is used as the base of the Rabin
// fingerprint algorithm
explicit HashFn(int p, bool precompute = true) {
this->p = p;
this->precompute = precompute;
if (precompute) {
uint64_t result = 1;
for (int i = 0; i < precomputedArraySize; i++) {
precomputedPowers[i] = result;
result *= p;
}
}
}
//virtual ~HashFn(){}
~HashFn(){}
virtual uint64_t operator()(const char *input, int len,
unsigned char lastCharCode, uint64_t lastHash);
virtual uint64_t operator()(const char *input, int len);
private:
int p;
bool precompute;
uint64Array precomputedPowers;
};
#endif // HASHFN_H_
hashFn.cc -->
#include "hashFn.h"
uint64_t HashFn::operator()(const char *input, int len,
unsigned char lastCharCode, uint64_t lastHash) {
// See the abracadabra example:
// https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm
return (lastHash - lastCharCode *
customPow(&precomputedPowers, precompute, p, len - 1)) *
p + input[len - 1];
}
uint64_t HashFn::operator()(const char *input, int len) {
uint64_t total = 0;
for (int i = 0; i < len; i++) {
total += input[i] *
customPow(&precomputedPowers, precompute, p, len - i - 1);
}
return total;
}
There is already a derived class from HashFn:
class HashFn2Byte : public HashFn {
public:
HashFn2Byte() : HashFn(0, false) {
}
uint64_t operator()(const char *input, int len,
unsigned char lastCharCode, uint64_t lastHash) override;
uint64_t operator()(const char *input, int len) override;
};
......
What went wrong? I can vaguely understand this has something to do with the virtual destructor but not sure why the vtable is undefined (if I define all declarations then vtable should be there automatically?).
Also, I'm now playing in Chromium so I don't know how would the fact all files are compiled into a "jumbo" object affect the results. The standalone version of this code (a Node native module) can compile and run normally.
Any input is appreciated! Thanks.
Related
There is some linking error here. I looked for that online, yet still I couldn't find the problem. How can I fix it?
g++ test.cpp -o test
/tmp/ccDfCj4N.o: In function `Interval::Interval()':
test.cpp:(.text._ZN8IntervalC2Ev[Interval::Interval()]+0x9): undefined reference to `vtable for Interval'
/tmp/ccDfCj4N.o: In function `IntInterval::~IntInterval()':
test.cpp:(.text._ZN11IntIntervalD0Ev[IntInterval::~IntInterval()]+0x1d): undefined reference to `Interval::~Interval()'
/tmp/ccDfCj4N.o: In function `IntInterval::~IntInterval()':
test.cpp:(.text._ZN11IntIntervalD1Ev[IntInterval::~IntInterval()]+0x1d): undefined reference to `Interval::~Interval()'
/tmp/ccDfCj4N.o:(.rodata._ZTI11IntInterval[typeinfo for IntInterval]+0x10): undefined reference to `typeinfo for Interval'
collect2: ld returned 1 exit status
Here is the code!
All classes are in a same file for a pilot program.
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
#define MAX_IP_RANGE 4294967295
class Interval {
public:
virtual Interval * interval_copy() = 0;
virtual unsigned long get_begin() = 0;
virtual unsigned long get_end() = 0;
virtual unsigned long get_length() = 0;
virtual Interval* get_intersect(Interval *interval) = 0; // Examine whether two intervals have intersection
virtual Interval* copy() = 0;
virtual ~Interval();
virtual bool is_equal(Interval *interval) {
unsigned long b1 = this->get_begin();
unsigned long e1 = this->get_end();
unsigned long b2 = interval->get_begin();
unsigned long e2 = interval->get_end();
if (b1 == b2 && e1 == e2)
return true;
return false;
}
virtual bool is_within(Interval *interval) {
unsigned long b1 = this->get_begin();
unsigned long e1 = this->get_end();
unsigned long b2 = interval->get_begin();
unsigned long e2 = interval->get_end();
if (b1 >= b2 && e1 <= e2)
return true;
return false;
}
virtual bool contains(Interval *interval) { // Examine whether this interval contains another interval
unsigned long b1 = this->get_begin();
unsigned long e1 = this->get_end();
unsigned long b2 = interval->get_begin();
unsigned long e2 = interval->get_end();
if (b1 <= b2 && e1 >= e2)
return true;
return false;
}
virtual bool is_empty() {
return (get_end()<get_begin())?true:false;
}
virtual bool is_intersect(Interval *interval) {
unsigned long b1 = this->get_begin();
unsigned long e1 = this->get_end();
unsigned long b2 = interval->get_begin();
unsigned long e2 = interval->get_end();
if (b1>e2)
return false;
if (b2>e1)
return false;
return true;
}
virtual void print()
{
cout << '('<<get_begin() << ',' << get_end() << ")\n";
}
};
class IntInterval : public Interval {
private:
unsigned long begin;
unsigned long end;
IntInterval();
public:
virtual Interval * interval_copy() {
return new IntInterval(begin, end);
}
IntInterval(unsigned long a, unsigned long b): begin (a), end (b)
{}
void set_value(unsigned long a, unsigned long b) {
begin = a;
end = b;
}
void set_begin(unsigned long a) {
begin = a;
}
void set_end(unsigned long b) {
end = b;
}
virtual Interval* copy()
{
Interval *new_interval = new IntInterval(begin, end);
return new_interval;
}
virtual unsigned long get_begin() {
return begin;
}
virtual unsigned long get_length() {
return end-begin+1;
}
virtual unsigned long get_end() {
return end;
}
virtual Interval* get_intersect(Interval *interval); // Get the intersect part of two intervals
virtual ~IntInterval() {};
};
Interval* IntInterval::get_intersect(Interval *interval) {
unsigned long begin2 = interval->get_begin();
unsigned long end2 = interval->get_end();
if (end < begin2 || begin > end2) {
return new IntInterval(1, 0);
}
return new IntInterval((begin>begin2)?begin:begin2, (end<end2)?end:end2);
}
IntInterval * parse_ip(const char * _str) {
unsigned long _begin=0;
unsigned long _end=0;
string input(_str);
if (input.find('-') != string::npos){
string begin = input.substr(0, input.find('-'));
string end = input.substr(input.find('-')+1);
unsigned int ip1 = 0, ip2 = 0;
unsigned int ip3 = 0, ip4 = 0;
sscanf(begin.c_str(), "%u.%u.%u.%u", &ip1, &ip2, &ip3, &ip4);
_begin = (ip1 << 24) + (ip2 << 16) + (ip3 << 8) + ip4;
ip1 = 0; ip2 = 0; ip3 = 0; ip4 = 0;
sscanf(end.c_str(), "%u.%u.%u.%u", &ip1, &ip2, &ip3, &ip4);
_end = (ip1 << 24) + (ip2 << 16) + (ip3 << 8) + ip4;
if ((_begin > _end) || (_end > MAX_IP_RANGE)){
cout<<"ERROR: The IP INTERVAL IS WRONG The range is "<<begin<<"-"<<end<<endl;
exit(0);
}
}
return new IntInterval(_begin, _end);
}
bool compFunc (Interval * i, Interval * j) {
return (i->get_begin() < j->get_begin());
}
int main () {
vector <vector<pair<string, string> > > nets;
vector<pair<string, string> > x;
vector<pair<string, string> > y;
x.push_back(make_pair("1.1.1.1", "3.0.0.0"));
x.push_back(make_pair("10.2.5.3", "30.2.5.0"));
x.push_back(make_pair("100.2.25.2", "130.2.25.2"));
y.push_back(make_pair("41.0.2.2", "43.2.2.5"));
y.push_back(make_pair("131.2.2.2", "135.5.5.2"));
nets.push_back(x);
nets.push_back(y);
vector <IntInterval *> _nets;
for (int i=0; i<(int)nets.size(); i++)
for(int j=0; j<(int)nets[i].size(); j++) {
string s = nets[i][j].first + '-' + nets[i][j].second;
_nets.push_back(parse_ip(s.c_str()));
}
sort(_nets.begin(), _nets.end(), compFunc);
if (_nets.size()>1)
for (vector<IntInterval *>::iterator it = _nets.begin()+1; it < _nets.end(); ) {
if ((*it)->get_begin()-1 == (*(it-1))->get_end()) {
(*(it-1))->set_end((*it)->get_end());
_nets.erase(it);
}
else if ((*it)->get_begin()-1 < (*(it-1))->get_end()) {
it++;
cout<<"ERROR: Network address overlapping!"<<endl;
}
else
it++;
}
for (int i=0; i<(int)_nets.size(); i++)
cout << _nets[i]->get_begin() << " " << _nets[i]->get_end() << endl;
return 0;
}
You never provided an implementation for virtual ~Interval(); and several other functions. You must provide an implementation for all non-pure virtual functions you declare. In particular, G++ emits the vtable along with the implementation of the first-declared non-inline function in a class. Omitting its implementation means you won't have a vtable, and thus won't be able to construct the class (hence these errors).
In short, define every function you declare, except for pure virtuals. There are some cases where it's justified to leave out the definition for a declared function, but they are very rare.
I had the same problem. I was merging my code with upstream changes and picked my change over another engineer's seemingly identical change in the header file. It just turned out that they had changed the constness of the method and I hadn't noticed, and you will get this error for the reason #bdonian says.
virtual void foo(Many params, As part, Of veryLong, Method signature);
and theirs:
virtual void foo(Many params, As part, Of veryLong, Method signature) const;
When merging I picked the first version, but the implementation had the second one, resulting in the compiler assuming there is an overload of foo() that is undefined, and hence the error.
In virtual classes never put undefined functions first. Move
IntInterval();
to after the first defined function:
private:
unsigned long begin;
unsigned long end;
public:
virtual Interval * interval_copy(){return new IntInterval(begin,end);}
IntInterval(unsigned long a,unsigned long b): begin (a),
end (b)
{}
private:
IntInterval();
public:
It's because C++ glues the vtable to the first function. If you don't define it, the vtable will be undefined as well.
As mentioned by other answers, you need to also define the destructor:
public:
virtual ~IntInterval()
{
// Destruction code
}
I receive this error:
In function 'bool detect_feedback(AudioEffect*)':
54:30: error: cannot convert 'std::shared_ptr<AudioEffect>' to 'AudioEffect*' in assignment
55:16: error: cannot convert 'std::shared_ptr<AudioEffect>' to 'AudioEffect*' in assignment
55:40: error: cannot convert 'std::shared_ptr<AudioEffect>' to 'AudioEffect*' in assignment
The code is as follows:
#include<stdlib.h>
#include<iostream>
#include<memory>`
//BASE CLASS
// audio and have a subsequent effect (next).
struct AudioEffect
{
virtual ~AudioEffect() = default;
virtual void process(float* buf, size_t num) = 0;
std::shared_ptr<AudioEffect> next;
};
//DERIVING MULTIPLE AUDIO-EFFECTS
//Noise Gate
struct NoiseGate: public AudioEffect
{
float threshold;
void process(float *buf, size_t num)
{
if (*buf > threshold)
*buf = threshold;
}
};
//Gain Boost
struct GainBoost: public AudioEffect
{
float signal;
void process(float *buf, size_t num)
{
*buf = *buf + signal;
}
};
//Compressor
struct Compressor: public AudioEffect
{
float offset;
void process(float *buf, size_t num)
{
*buf = *buf - offset;
}
};
//Function
// Implement a function that checks if there is a feedback loop
// in the effects chain.
//... detect_feedback(...)
//{
//}
bool detect_feedback (AudioEffect *ae)
{
AudioEffect *p, *q;
for (p = ae;p != NULL; p = p->next)
for (q = p->next; q != NULL; q = q->next)
if (typeid(*p) == typeid(*q))
return true;
return false;
}
//MAIN
int main(int argc, char *argv[])
{
return 0;
}
You can not assign a shared_ptr to a raw pointer. You need to use the .get() method to obtain a raw pointer.
(p->next).get()
I am trying to code a C++ implementation of a Bloom filter using the MurmurHash3 hash function. My implementation is based on this site: http://blog.michaelschmatz.com/2016/04/11/how-to-write-a-bloom-filter-cpp/
Somehow, in my BloomFilter header file, the hash function throws an incomplete type error, also, when I use the hash function inside of the add function, I get a "hash is ambigious error".
What can I do to fix this? I am somewhat new to C++ so I'm not exactly sure if I am using the interface/implementation of a structure correctly.
I am also using a main function that will include this file and run some tests to analyze the false positive rate, number of bits, filter size etc . . .
#ifndef BLOOM_FILTER_H
#define BLOOM_FILTER_H
#include "MurmurHash3.h"
#include <vector>
//basic structure of a bloom filter object
struct BloomFilter {
BloomFilter(uint64_t size, uint8_t numHashes);
void add(const uint8_t *data, std::size_t len);
bool possiblyContains(const uint8_t *data, std::size_t len) const;
private:
uint8_t m_numHashes;
std::vector<bool> m_bits;
};
//Bloom filter constructor
BloomFilter::BloomFilter(uint64_t size, uint8_t numHashes)
: m_bits(size),
m_numHashes(numHashes) {}
//Hash array created using the MurmurHash3 code
std::array<uint64_t, 2> hash(const uint8_t *data, std::size_t len)
{
std::array<uint64_t, 2> hashValue;
MurmurHash3_x64_128(data, len, 0, hashValue.data());
return hashValue;
}
//Hash array created using the MurmurHash3 code
inline uint64_t nthHash(uint8_t n,
uint64_t hashA,
uint64_t hashB,
uint64_t filterSize) {
return (hashA + n * hashB) % filterSize;
}
//Adds an element to the array
void BloomFilter::add(const uint8_t *data, std::size_t len) {
auto hashValues = hash(data, len);
for (int n = 0; n < m_numHashes; n++)
{
m_bits[nthHash(n, hashValues[0], hashValues[1], m_bits.size())] = true;
}
}
//Returns true or false based on a probabilistic assesment of the array using MurmurHash3
bool BloomFilter::possiblyContains(const uint8_t *data, std::size_t len) const {
auto hashValues = hash(data, len);
for (int n = 0; n < m_numHashes; n++)
{
if (!m_bits[nthHash(n, hashValues[0], hashValues[1], m_bits.size())])
{
return false;
}
}
return true;
}
#endif
If your MurmurHash3_x64_128 returns two 64-bit numbers as a hash value, I'd treat that as 4 distinct uint32_t hashes as long as you don't need more than 4 billion bits in your bit string. Most likely you don't need more than 2-3 hashses, but that depends on your use case. To figure out how many hashes you need you can check "How many hash functions does my bloom filter need?".
Using MurmurHash3_x64_128 I'd do it this way (if I were to treat it as 4 x uint32_t hashses):
void BloomFilter::add(const uint8_t *data, std::size_t len) {
auto hashValues = hash(data, len);
uint32_t* hx = reinterpret_cast<uint32_t*>(&hashValues[0]);
assert(m_numHashes <= 4);
for (int n = 0; n < m_numHashes; n++)
m_bits[hx[n] % m_bits.size()] = true;
}
Your code has some issues with types conversion that's why it didn't compile:
missing #include <array>
you have to use size_t for size (it might be 32-bit unsigned or 64-bit unsigned int)
it's better to name your hash to something else (e.g. myhash) and make it static.
Here's version of your code with these correction and this should work:
#ifndef BLOOM_FILTER_H
#define BLOOM_FILTER_H
#include "MurmurHash3.h"
#include <vector>
#include <array>
//basic structure of a bloom filter object
struct BloomFilter {
BloomFilter(size_t size, uint8_t numHashes);
void add(const uint8_t *data, std::size_t len);
bool possiblyContains(const uint8_t *data, std::size_t len) const;
private:
uint8_t m_numHashes;
std::vector<bool> m_bits;
};
//Bloom filter constructor
BloomFilter::BloomFilter(size_t size, uint8_t numHashes)
: m_bits(size),
m_numHashes(numHashes) {}
//Hash array created using the MurmurHash3 code
static std::array<uint64_t, 2> myhash(const uint8_t *data, std::size_t len)
{
std::array<uint64_t, 2> hashValue;
MurmurHash3_x64_128(data, len, 0, hashValue.data());
return hashValue;
}
//Hash array created using the MurmurHash3 code
inline size_t nthHash(int n,
uint64_t hashA,
uint64_t hashB,
size_t filterSize) {
return (hashA + n * hashB) % filterSize; // <- not sure if that is OK, perhaps it is.
}
//Adds an element to the array
void BloomFilter::add(const uint8_t *data, std::size_t len) {
auto hashValues = myhash(data, len);
for (int n = 0; n < m_numHashes; n++)
{
m_bits[nthHash(n, hashValues[0], hashValues[1], m_bits.size())] = true;
}
}
//Returns true or false based on a probabilistic assesment of the array using MurmurHash3
bool BloomFilter::possiblyContains(const uint8_t *data, std::size_t len) const {
auto hashValues = myhash(data, len);
for (int n = 0; n < m_numHashes; n++)
{
if (!m_bits[nthHash(n, hashValues[0], hashValues[1], m_bits.size())])
{
return false;
}
}
return true;
}
#endif
Run this code on ideone.
If you are just starting with c++, at first start with basic example, try to use std::hash maybe? Create working implementation, then extend it with optional hash function parameter. If you need your BloomFilter to be fast I'd probably stay away from vector<bool> and use array of unsigned ints instead.
Basic impl could something like this, provided that your have MurmurHash3 implemented:
uint32_t MurmurHash3(const char *str, size_t len);
class BloomFilter
{
public:
BloomFilter(int count_elements = 0, double bits_per_element = 10)
{
mem = NULL;
init(count_elements, bits_per_element);
}
~BloomFilter()
{
delete[] mem;
}
void init(int count_elements, double bits_per_element)
{
assert(!mem);
sz = (uint32_t)(count_elements*bits_per_element + 0.5);
mem = new uint8_t[sz / 8 + 8];
}
void add(const std::string &str)
{
add(str.data(), str.size());
}
void add(const char *str, size_t len)
{
if (len <= 0)
return;
add(MurmurHash3(str, len));
}
bool test(const std::string &str)
{
return test(str.data(), str.size());
}
bool test(const char *str, size_t len)
{
return test_hash(MurmurHash3(str, len));
}
bool test_hash(uint32_t h)
{
h %= sz;
if (0 != (mem[h / 8] & (1u << (h % 8))))
return true;
return false;
}
int mem_size() const
{
return (sz + 7) / 8;
}
private:
void add(uint32_t h)
{
h %= sz;
mem[h / 8] |= (1u << (h % 8));
}
public:
uint32_t sz;
uint8_t *mem;
};
I've a structure DutPlayerArrayElement defined in following lines:
namespace Common
{
namespace Constants {
const int MaxNumberOfIPAddresses = 10;
const int NumberOFRFOutputs = 100;
const int NumberOfPlayers = 100;
const int SignalFileNameSize = 30;
}
enum AntennaType
{
Omni = 0,
Directive,
Custom,
InvalidAntenna
};
enum ModulationID
{
CW = 0,
SSB,
LSB,
AM,
FM,
WFM,
DVBT
};
enum SigFileID
{
SIG_FILE_ID_ARB12 = 1,
SIG_FILE_ID_ARB16,
SIG_FILE_ID_WAV,
SIG_FILE_ID_TXT
};
typedef struct
{
//Basic
double dLatitude;
double dLongitude;
double dAltitude;
double dHeading;
float fNorthSudVelocity;
float fEastOvestVelocity;
float fVerticalVelocity;
unsigned int uiIsValid;
bool bIsDestroyed;
bool bTxIsOn;
ModulationID xModulationID;
SigFileID xSigFileType ;
char cSigFileName[128];
bool bLoopPlayback ;
char cAntennaTableFile[128];
bool bUseAntGainFactor;
double dAntGainFactor;
double dAntennaOrientation;
double dCarrierFrequency;
bool bTxIsLOS;
double dPwr;
double dAzimuth;
double dElevation;
double dDistance;
char cEntityName[128];
//char cModulation[2];
}PlayerArrayElement;
typedef struct
{
//Basic
double dLatitude;
double dLongitude;
double dAltitude;
double dHeading;
float fNorthSudVelocity;
float fEastOvestVelocity;
float fVerticalVelocity;
bool bIsDestroyed;
unsigned int uiNumAssignedRFOut;
bool bIsSync;
unsigned int uiNumRFOutXIP;
int iAssignedRFOut[Constants::NumberOFRFOutputs];
unsigned int uiRfGenCount;
int iIpAddress[Constants::MaxNumberOfIPAddresses];
unsigned int xPort[10];
double xCarrierFrequency[10];
//AntennaType xAntennatype;
char cAntennaTableFile[128];
bool bUseAntGainFactor;
double dAntGainFactor;
double dAntennaOrientation;
unsigned int uiNumOfPlayer;
PlayerArrayElement xScenarioPlayer[Constants::NumberOfPlayers];
char cEntityName[128];
unsigned int uiIsValid;
bool simIsRunning;
} DutPlayerArrayElement;
typedef std::vector<DutPlayerArrayElement> DutPlayers;
}
I also define a typedef std::vector<DutPlayerArrayElement> DutPlayers;
In a Visual studio 2008 library, I declare a class with this vector as member:
class COM_API MyClass
{
public:
SimComintManager();
~SimComintManager() ;
bool init();
void runme();
private:
void setup();
private:
// ....
Common::DutPlayers m_xDutPlayers;
// other structures...
};
in runme method:
void MyClass::runme()
{
while(m_bScenarioIsRunning)
{
if(m_uiIterationCount == 0)
{
m_pGen->setRfOutState(0, ON);
}
else
{
//aggiornare RF scenario in base a SHM attuale
m_xDutPlayers.clear() ;
m_xShmReader.getData(m_xDutPlayers) ;
}
}
}
ShmReader is a class defined in another library, that uses the same .h file in which vector is defined:
bool Reader::getData( Common::DutPlayers& xDutVector)
{
Common::DutPlayerArrayElement xEntityArrayElement;
for(int i = 0; i < m_iNumberOfEntities; i++)
{
xEntityArrayElement = m_pxPlayerShmVector->getValue(i);
if(xEntityArrayElement.uiIsValid == 1)
m_bSimulationState = xEntityArrayElement.simIsRunning;
xDutVector.push_back(xEntityArrayElement);
}
return true;
}
When I call xDutVector.push_back(xEntityArrayElement); I've an error and program crashes. Visual studio says Microsoft Visual Studio C Runtime Library has detected a fatal error in program.exe and when I click Break button the callstack is in row 161 of vector.h, the _SCL_SECURE_VALIDATE_RANGE row of this piece of code:
_Myt& operator+=(difference_type _Off)
{ // increment by integer
_SCL_SECURE_VALIDATE(this->_Has_container());
_SCL_SECURE_VALIDATE_RANGE(
_Myptr + _Off <= ((_Myvec *)(this->_Getmycont()))->_Mylast &&
_Myptr + _Off >= ((_Myvec *)(this->_Getmycont()))->_Myfirst);
_Myptr += _Off;
return (*this);
}
I've googled a bit and I've found this error regarding iterator erasing, but nothing regarding the push_back. What I'm doing wrong and how can I use push_back correctly?
There is some linking error here. I looked for that online, yet still I couldn't find the problem. How can I fix it?
g++ test.cpp -o test
/tmp/ccDfCj4N.o: In function `Interval::Interval()':
test.cpp:(.text._ZN8IntervalC2Ev[Interval::Interval()]+0x9): undefined reference to `vtable for Interval'
/tmp/ccDfCj4N.o: In function `IntInterval::~IntInterval()':
test.cpp:(.text._ZN11IntIntervalD0Ev[IntInterval::~IntInterval()]+0x1d): undefined reference to `Interval::~Interval()'
/tmp/ccDfCj4N.o: In function `IntInterval::~IntInterval()':
test.cpp:(.text._ZN11IntIntervalD1Ev[IntInterval::~IntInterval()]+0x1d): undefined reference to `Interval::~Interval()'
/tmp/ccDfCj4N.o:(.rodata._ZTI11IntInterval[typeinfo for IntInterval]+0x10): undefined reference to `typeinfo for Interval'
collect2: ld returned 1 exit status
Here is the code!
All classes are in a same file for a pilot program.
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
#define MAX_IP_RANGE 4294967295
class Interval {
public:
virtual Interval * interval_copy() = 0;
virtual unsigned long get_begin() = 0;
virtual unsigned long get_end() = 0;
virtual unsigned long get_length() = 0;
virtual Interval* get_intersect(Interval *interval) = 0; // Examine whether two intervals have intersection
virtual Interval* copy() = 0;
virtual ~Interval();
virtual bool is_equal(Interval *interval) {
unsigned long b1 = this->get_begin();
unsigned long e1 = this->get_end();
unsigned long b2 = interval->get_begin();
unsigned long e2 = interval->get_end();
if (b1 == b2 && e1 == e2)
return true;
return false;
}
virtual bool is_within(Interval *interval) {
unsigned long b1 = this->get_begin();
unsigned long e1 = this->get_end();
unsigned long b2 = interval->get_begin();
unsigned long e2 = interval->get_end();
if (b1 >= b2 && e1 <= e2)
return true;
return false;
}
virtual bool contains(Interval *interval) { // Examine whether this interval contains another interval
unsigned long b1 = this->get_begin();
unsigned long e1 = this->get_end();
unsigned long b2 = interval->get_begin();
unsigned long e2 = interval->get_end();
if (b1 <= b2 && e1 >= e2)
return true;
return false;
}
virtual bool is_empty() {
return (get_end()<get_begin())?true:false;
}
virtual bool is_intersect(Interval *interval) {
unsigned long b1 = this->get_begin();
unsigned long e1 = this->get_end();
unsigned long b2 = interval->get_begin();
unsigned long e2 = interval->get_end();
if (b1>e2)
return false;
if (b2>e1)
return false;
return true;
}
virtual void print()
{
cout << '('<<get_begin() << ',' << get_end() << ")\n";
}
};
class IntInterval : public Interval {
private:
unsigned long begin;
unsigned long end;
IntInterval();
public:
virtual Interval * interval_copy() {
return new IntInterval(begin, end);
}
IntInterval(unsigned long a, unsigned long b): begin (a), end (b)
{}
void set_value(unsigned long a, unsigned long b) {
begin = a;
end = b;
}
void set_begin(unsigned long a) {
begin = a;
}
void set_end(unsigned long b) {
end = b;
}
virtual Interval* copy()
{
Interval *new_interval = new IntInterval(begin, end);
return new_interval;
}
virtual unsigned long get_begin() {
return begin;
}
virtual unsigned long get_length() {
return end-begin+1;
}
virtual unsigned long get_end() {
return end;
}
virtual Interval* get_intersect(Interval *interval); // Get the intersect part of two intervals
virtual ~IntInterval() {};
};
Interval* IntInterval::get_intersect(Interval *interval) {
unsigned long begin2 = interval->get_begin();
unsigned long end2 = interval->get_end();
if (end < begin2 || begin > end2) {
return new IntInterval(1, 0);
}
return new IntInterval((begin>begin2)?begin:begin2, (end<end2)?end:end2);
}
IntInterval * parse_ip(const char * _str) {
unsigned long _begin=0;
unsigned long _end=0;
string input(_str);
if (input.find('-') != string::npos){
string begin = input.substr(0, input.find('-'));
string end = input.substr(input.find('-')+1);
unsigned int ip1 = 0, ip2 = 0;
unsigned int ip3 = 0, ip4 = 0;
sscanf(begin.c_str(), "%u.%u.%u.%u", &ip1, &ip2, &ip3, &ip4);
_begin = (ip1 << 24) + (ip2 << 16) + (ip3 << 8) + ip4;
ip1 = 0; ip2 = 0; ip3 = 0; ip4 = 0;
sscanf(end.c_str(), "%u.%u.%u.%u", &ip1, &ip2, &ip3, &ip4);
_end = (ip1 << 24) + (ip2 << 16) + (ip3 << 8) + ip4;
if ((_begin > _end) || (_end > MAX_IP_RANGE)){
cout<<"ERROR: The IP INTERVAL IS WRONG The range is "<<begin<<"-"<<end<<endl;
exit(0);
}
}
return new IntInterval(_begin, _end);
}
bool compFunc (Interval * i, Interval * j) {
return (i->get_begin() < j->get_begin());
}
int main () {
vector <vector<pair<string, string> > > nets;
vector<pair<string, string> > x;
vector<pair<string, string> > y;
x.push_back(make_pair("1.1.1.1", "3.0.0.0"));
x.push_back(make_pair("10.2.5.3", "30.2.5.0"));
x.push_back(make_pair("100.2.25.2", "130.2.25.2"));
y.push_back(make_pair("41.0.2.2", "43.2.2.5"));
y.push_back(make_pair("131.2.2.2", "135.5.5.2"));
nets.push_back(x);
nets.push_back(y);
vector <IntInterval *> _nets;
for (int i=0; i<(int)nets.size(); i++)
for(int j=0; j<(int)nets[i].size(); j++) {
string s = nets[i][j].first + '-' + nets[i][j].second;
_nets.push_back(parse_ip(s.c_str()));
}
sort(_nets.begin(), _nets.end(), compFunc);
if (_nets.size()>1)
for (vector<IntInterval *>::iterator it = _nets.begin()+1; it < _nets.end(); ) {
if ((*it)->get_begin()-1 == (*(it-1))->get_end()) {
(*(it-1))->set_end((*it)->get_end());
_nets.erase(it);
}
else if ((*it)->get_begin()-1 < (*(it-1))->get_end()) {
it++;
cout<<"ERROR: Network address overlapping!"<<endl;
}
else
it++;
}
for (int i=0; i<(int)_nets.size(); i++)
cout << _nets[i]->get_begin() << " " << _nets[i]->get_end() << endl;
return 0;
}
You never provided an implementation for virtual ~Interval(); and several other functions. You must provide an implementation for all non-pure virtual functions you declare. In particular, G++ emits the vtable along with the implementation of the first-declared non-inline function in a class. Omitting its implementation means you won't have a vtable, and thus won't be able to construct the class (hence these errors).
In short, define every function you declare, except for pure virtuals. There are some cases where it's justified to leave out the definition for a declared function, but they are very rare.
I had the same problem. I was merging my code with upstream changes and picked my change over another engineer's seemingly identical change in the header file. It just turned out that they had changed the constness of the method and I hadn't noticed, and you will get this error for the reason #bdonian says.
virtual void foo(Many params, As part, Of veryLong, Method signature);
and theirs:
virtual void foo(Many params, As part, Of veryLong, Method signature) const;
When merging I picked the first version, but the implementation had the second one, resulting in the compiler assuming there is an overload of foo() that is undefined, and hence the error.
In virtual classes never put undefined functions first. Move
IntInterval();
to after the first defined function:
private:
unsigned long begin;
unsigned long end;
public:
virtual Interval * interval_copy(){return new IntInterval(begin,end);}
IntInterval(unsigned long a,unsigned long b): begin (a),
end (b)
{}
private:
IntInterval();
public:
It's because C++ glues the vtable to the first function. If you don't define it, the vtable will be undefined as well.
As mentioned by other answers, you need to also define the destructor:
public:
virtual ~IntInterval()
{
// Destruction code
}