Solved

Differs in level of redirection

Posted on 2013-02-05
18
283 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 7
  • 2
  • +1
18 Comments
 
LVL 22

Assisted Solution

by:ambience
ambience earned 50 total points
ID: 38855656
>>  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
ID: 38855687
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
ID: 38855817
Your example compiles just fine - could you post the actual code that is failing, or at least parts of it?
0
Transaction Monitoring Vs. Real User Monitoring

Synthetic Transaction Monitoring Vs. Real User Monitoring: When To Use Each Approach? In this article, we will discuss two major monitoring approaches: Synthetic Transaction and Real User Monitoring.

 
LVL 34

Assisted Solution

by:sarabande
sarabande earned 100 total points
ID: 38856314
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
ID: 38856408
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
ID: 38856430
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
ID: 38856437
>>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
ID: 38856501
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
ID: 38856535
@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
 
LVL 86

Expert Comment

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

Author Comment

by:farzanj
ID: 38856836
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
ID: 38856894
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
ID: 38857005
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
ID: 38857045
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
ID: 38858070
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
ID: 38858122
>>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 34

Expert Comment

by:sarabande
ID: 38860754
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
ID: 38875240
Thank you all for your time.  Sara, I would definitely benchmark your type of solution.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When we want to run, execute or repeat a statement multiple times, a loop is necessary. This article covers the two types of loops in Python: the while loop and the for loop.
Computer science students often experience many of the same frustrations when going through their engineering courses. This article presents seven tips I found useful when completing a bachelors and masters degree in computing which I believe may he…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

717 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