Solved

Differs in level of redirection

Posted on 2013-02-05
18
278 Views
Last Modified: 2013-02-11
This is follow up for discussion in:

http://www.experts-exchange.com/Programming/Languages/CPP/Q_28019385.html#a38852420

This is just a pseudo example of my actual work.  Now there appears to be some difference because it compiles and the actual one has the following errror:

PmdsParser' differs in levels of indirection from 'std::string [14]'
1>  pmds_parser.cpp

This in this example would make it class B.  I wonder if you can guess it by looking at this analogous example or I can offer excerpts on your request.

You may also offer any more advice from the previous discussion.

#include<iostream>
#include<string>

using namespace std;

const int  num = 10;

string vals[num] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th"};

class A
{
public:
	A(string* s1, string* s2, const int& n1) : n(n1)
	{
		//n  = n1;
		v1 = s1;
		v2 = s2;
	}
	void copy()
	{
		for(int i=0; i < n; i++)
		{
			v2[i] = v1[i];
		}
	}
protected:
	const int&    n;
	string* v1;
	string* v2;
};

class B : public A
{
public:
	B(string* s, int& n) : A(vals, s, n) // call base class constructor from initializer list
	{
	}
};


int main()
{
	const int COUNT = 10;
	string ans[COUNT];
    int n1 = num;
	B b(ans, n1);
	b.copy();
	for(int i=0; i < num; i++)
	{
		cout << ans[i] << endl;
	}
	cin.get();

	return 0;
}

Open in new window

0
Comment
Question by:farzanj
  • 8
  • 7
  • 2
  • +1
18 Comments
 
LVL 22

Assisted Solution

by:ambience
ambience earned 50 total points
Comment Utility
>>  I wonder if you can guess it by looking at this analogous example or I can offer excerpts on your request.

Hard to guess. Can you post the real piece? OR an exact replica?
0
 
LVL 31

Author Comment

by:farzanj
Comment Utility
Hi Sara,
To your comment in the last discussion.
Here's my design, I have a parser class which will have many sub classes.  Each of these sub classes will have a list of tokens that I need to pass, may be I should not store pointer instead the whole array, I don't know.  Then the client program uses these sub classes and sends lines to each parser subclass to be parsed according to their types.  I am initializing tokens in the sub classes as the parser is more generic.  Sub classes are specific to one kind of input and they will override some members of the parent class as well.  Once a parser is initialized, I do not want any noise of sending so many arrays in every call.  I just want to sent a single record that needs to be parsed.

The token arrays are used trillions of times and I want that access to be as fast as possible.  Theoretically, I think that keeping it in the stack and not using vector makes it faster.  Do you disagree?
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
Your example compiles just fine - could you post the actual code that is failing, or at least parts of it?
0
 
LVL 32

Assisted Solution

by:sarabande
sarabande earned 100 total points
Comment Utility
the creation of a static array of literals is a one-time operation where it makes no difference whether it is created on the stack (c array) or on the heap (vector). you even could use both as I did in my recent code: have a static c array defining the literals and use that to feed a vector. that is very convenient cause you could use static initialization and have the full advantage a std::vector has over a c array.

however, to avoid redundancy both the members should static in class B (or a further derived class).  

class B : public A
{
       static const char * vals[num_vals];
       static std::vector<std::string> v;
public:
};

// static initialisation
const char * B::vals[num_vals] = {"first", "second", "third", "fourth", "Fifth", "6th", "7th", "8th", "9th", "10th", };
std::vector<std::string> B::v(&vals[0], &vals[num_vals]);

Open in new window


you see that baseclass A is not needed until now. if you now want to get the tokens from class B you simply should provide a get function that returns the array:

class B
{
     ....
public:
    static const std::vector<std::string>& get_tokens() { return v; }

Open in new window


the above would allo to directly get access of the static array of class B like with

int main()
{
     ...
     std::vector<std::string>  ans = B::get_tokens();

Open in new window


that makes a writeable copy out of tokens and because get_tokens is static you don't need an instance of B to call the function.

if your program doesn't want/need to change the array or the array elements you alternatively can use a reference:

int main()
{
     ...
     const std::vector<std::string>  & ans = B::get_tokens();

Open in new window


that only would return a constant reference (address) and would not create a copy. so of course that is fastest as long as you not need to change the array data.

you also see that for this, the baseclass A was not needed though you also could provide a virtual function what would allow class A to virtually retrieve the tokens array from derived class and provide parsing functionality by baseclass members:

class A
{
protected:
     virtual std::vector<std::string> & tokens() = 0; // makes it a pure virtual function
                                                                                   // must be overloaded by derived classes
public:
     int find_first_token(const std::string text)
     {
           std::vector<std::string> & v = tokens();  // virtual call
           // parse for tokens in text
           ... 

Open in new window


Sara
0
 
LVL 31

Author Comment

by:farzanj
Comment Utility
I was able to resolve the earlier error but now there are linking errors.  If you go to the test.cpp file, you will see a comment.  If you follow that instruction, it would remove the compilation error but the linking errors still remain.

I need the explanation why this error went away and the reason/solution of linking errors.
EE.zip
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 350 total points
Comment Utility
Well, you are using 'PmdsParser(string*, const int& n);' as a costructor, yet there is no implementaion of that one in the .cpp file, thus the error - it should go away if you provide an empty one and then fill it with meaningful code, e.g.

PmdsParser::PmdsParser(string*, const int& n) {

}

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
>>and then fill it with meaningful code

... and if that only would mean calling a base class' constructor (if there is one), e.g.

PmdsParser::PmdsParser(string* a, const int& n) : Parser(s,n) {}

Open in new window

0
 
LVL 31

Author Comment

by:farzanj
Comment Utility
Hi JKR,
Sorry, I lost you.  In pmds_parser.cpp file, I do have implementation of parser.

PmdsParser::PmdsParser(string* r, const int& n)  : Parser(TOKENS, TERMS, r, REQUIREMENT, DIRECTIONS, n)
{
}

Open in new window


If you comment one line mentioned in the test.cpp file and uncomment the alternate, it even compiles but I get linking errors which don't to have any issue with the constructor rather my constant globals appear to be an issue.

And I could not send the VC++ project files as EE doesn't accept it.
0
 
LVL 31

Assisted Solution

by:farzanj
farzanj earned 0 total points
Comment Utility
@Sara:  I am looking into your comments and they certainly present very good arguments.  I need to benchmark both the methods though.  Also, C++11 has Array instead of vectors, that is even more modern and powerful code than yours :)
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 86

Expert Comment

by:jkr
Comment Utility
Sorry, must have missed that - what exactly are the linker errors you are getting?
0
 
LVL 31

Author Comment

by:farzanj
Comment Utility
These are the errors:
1>------ Build started: Project: parserproj, Configuration: Debug Win32 ------
1>  test.cpp
1>  pmds_parser.cpp
1>  parser.cpp
1>  Generating Code...
1>test.obj : error LNK2005: "bool * DIRECTIONS" (?DIRECTIONS@@3PA_NA) already defined in pmds_parser.obj
1>test.obj : error LNK2005: "bool * REQUIREMENT" (?REQUIREMENT@@3PA_NA) already defined in pmds_parser.obj
1>test.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * TERMS" (?TERMS@@3PAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) already defined in pmds_parser.obj
1>test.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * TOKENS" (?TOKENS@@3PAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) already defined in pmds_parser.obj
1>test.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * FILTERS" (?FILTERS@@3PAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) already defined in pmds_parser.obj
1>C:\Users\fmufti\Desktop\C++Projects\EE\Debug\parserproj.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
Ah, I see - you can fix that by using a construct similar to a header guard, e.g.

#ifndef CONSTANTS_DEFINED
const bool AND      = true;
const bool OR       = false;
const bool FORWARD  = true;
const bool REVERSE  = false;
const bool REQUIRED = true;
const bool OPTIONAL = false;
const string DELIM   = "\t";
#define CONSTANTS_DEFINED
#else
extern const bool AND ;
extern const bool OR;
extern const bool FORWARD;
extern const bool REVERSE;
extern const bool REQUIRED;
extern const bool OPTIONAL;
extern const string DELIM;
#endif

Open in new window

0
 
LVL 31

Author Comment

by:farzanj
Comment Utility
Sorry, still the same.

I used the following:
#ifndef CONSTANT_DEFINED
#define CONSTANT_DEFINED
const int CAPTURE_COUNT = 13;
const int TOKEN_COUNT   = 14;
const int FILTER_COUNT  = 2;
bool DIRECTIONS[TOKEN_COUNT]  = {REVERSE, REVERSE, FORWARD, FORWARD, FORWARD, FORWARD, FORWARD,
                                               FORWARD, FORWARD, FORWARD, FORWARD, FORWARD, FORWARD};

bool REQUIREMENT[TOKEN_COUNT] = {REQUIRED, REQUIRED, REQUIRED, REQUIRED, REQUIRED, REQUIRED, 
	                                           OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL};

string TOKENS[TOKEN_COUNT]     = {" <", ">:", ":[", ":<", "LAYER =" ,"DEVICEPIN = ", "DOMAINNAME = ", "CONNECTION_TYPE = ",
                                      "ConnectionId = ", "DURATION(ms) = ", "MFH_KBytes = ", "MTH_KBytes = ", "MFH_PACKET_COUNT = ",
									  "MTH_PACKET_COUNT = "};

string TERMS[TOKEN_COUNT]      = {" ", "<", "]", ">", "", ",", ",", ",", ",", ",", ",", ",", ",", ">"};

string FILTERS[FILTER_COUNT]   = {"<INFO", "LAYER = IPPP"};

#else
extern const int CAPTURE_COUNT;
extern const int TOKEN_COUNT;
extern const int FILTER_COUNT;
extern bool DIRECTIONS[TOKEN_COUNT];

extern bool REQUIREMENT[TOKEN_COUNT];

extern string TOKENS[TOKEN_COUNT];

extern string TERMS[TOKEN_COUNT];

extern string FILTERS[FILTER_COUNT];
#endif

Open in new window


But still getting linking errors:
1>test.obj : error LNK2005: "bool * DIRECTIONS" (?DIRECTIONS@@3PA_NA) already defined in pmds_parser.obj
1>test.obj : error LNK2005: "bool * REQUIREMENT" (?REQUIREMENT@@3PA_NA) already defined in pmds_parser.obj
1>test.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * TERMS" (?TERMS@@3PAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) already defined in pmds_parser.obj
1>test.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * TOKENS" (?TOKENS@@3PAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) already defined in pmds_parser.obj
1>test.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > * FILTERS" (?FILTERS@@3PAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) already defined in pmds_parser.obj
1>C:\Users\fmufti\Desktop\C++Projects\EE\Debug\parserproj.exe : fatal error LNK1169: one or more multiply defined symbols found
0
 
LVL 86

Accepted Solution

by:
jkr earned 350 total points
Comment Utility
OK, then *only* use the 'extern' definitions and move the actual implementations to 'parser.cpp', i.e.

#ifndef PARSER_H
#define PARSER_H
#include<string>
#include<iostream>
#include<fstream>

using namespace std;

extern const bool AND ;
extern const bool OR;
extern const bool FORWARD;
extern const bool REVERSE;
extern const bool REQUIRED;
extern const bool OPTIONAL;
extern const string DELIM;
extern const int CAPTURE_COUNT;
extern const int TOKEN_COUNT;
extern const int FILTER_COUNT;
extern bool DIRECTIONS[TOKEN_COUNT];
extern bool REQUIREMENT[TOKEN_COUNT];
extern string TOKENS[TOKEN_COUNT];
extern string TERMS[TOKEN_COUNT];
extern string FILTERS[FILTER_COUNT];

// ...

Open in new window


#ifndef PARSER_CPP
#define PARSER_CPP
#include <iostream>
#include <fstream>
#include "parser.h"

using std::ofstream;
using std::getline;
using std::cerr;
using std::ios;

const bool AND      = true;
const bool OR       = false;
const bool FORWARD  = true;
const bool REVERSE  = false;
const bool REQUIRED = true;
const bool OPTIONAL = false;
const string DELIM   = "\t";
const int CAPTURE_COUNT = 13;
const int TOKEN_COUNT   = 14;
const int FILTER_COUNT  = 2;
bool DIRECTIONS[TOKEN_COUNT]  = {REVERSE, REVERSE, FORWARD, FORWARD, FORWARD, FORWARD, FORWARD,
                                               FORWARD, FORWARD, FORWARD, FORWARD, FORWARD, FORWARD};

bool REQUIREMENT[TOKEN_COUNT] = {REQUIRED, REQUIRED, REQUIRED, REQUIRED, REQUIRED, REQUIRED, 
	                                           OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL};

string TOKENS[TOKEN_COUNT]     = {" <", ">:", ":[", ":<", "LAYER =" ,"DEVICEPIN = ", "DOMAINNAME = ", "CONNECTION_TYPE = ",
                                      "ConnectionId = ", "DURATION(ms) = ", "MFH_KBytes = ", "MTH_KBytes = ", "MFH_PACKET_COUNT = ",
									  "MTH_PACKET_COUNT = "};

string TERMS[TOKEN_COUNT]      = {" ", "<", "]", ">", "", ",", ",", ",", ",", ",", ",", ",", ",", ">"};

string FILTERS[FILTER_COUNT]   = {"<INFO", "LAYER = IPPP"};

Open in new window

0
 
LVL 31

Author Comment

by:farzanj
Comment Utility
Ok, linking errors are gone by simply moving the constant declarations from pmds_parser.h to pmds_parser.cpp file.

One more issue is that I cannot declare a default constructor because apparently
const int&     token_count
 has to be initialized for the class to get initialized and I cannot do that in the default constructor because I need the value of token count from the client (test.cpp).  

So, MUST references always be initialized for objects?  How do I take care of this issue?
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 350 total points
Comment Utility
>>So, MUST references always be initialized for objects?
Yes, for there sheer nature (while being similar to poinbters, yet being something diferent

 >>How do I take care of this issue?

That's a matter of design then - does it really have to be a POD reference (here: 'int')? As stoopid as it might sound...

I mean, probably you do have a reason to use a refence here by having to use that value later on - so find a better way to do that instead of just pointing a class instance as the "dump point" for that value ;o)
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
yes the new standard c11 will be more powerful. i nevertheless  would suggest you to use the current standard which was released 1998 and therefore is used by most of current applications and you could draw on the experiences of many experts. the new standard will be based on the current standard (and i would guess it is better to do the first step before the second :) )

Sara
0
 
LVL 31

Author Closing Comment

by:farzanj
Comment Utility
Thank you all for your time.  Sara, I would definitely benchmark your type of solution.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
If you’re thinking to yourself “That description sounds a lot like two people doing the work that one could accomplish,” you’re not alone.
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now