Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

linker error

67 views
Skip to first unread message

alexo

unread,
May 12, 2017, 8:05:34 PM5/12/17
to
Hello all,
can you find the bug in this code snipped?
It is a class template I'm trying to write.
but the linker complains and reminds me I'm a beginner :(
thank you




#include <iostream>
#include <typeinfo>
#include <cstring>

using std::string;
using std::ostream;


/// the class' declaration


template <class T>
class MyClass
{
T *data;

public:
MyClass(T);
MyClass(const MyClass<T> &);
~MyClass();

friend ostream & operator<<(ostream &, const MyClass<T> &);

};


/// the class' definition


// constructor

template <class T>
MyClass<T>::MyClass(T val)
{
data = new T;
data = val;
}

// copy constructor

template <class T>
MyClass<T>::MyClass(const MyClass<T> &obj)
{
data = new T;

if( typeid(T) == typeid(char *) )
{
int len = strlen(obj.data);
strncpy(data, obj.data, len+1);
}
else
{
data = obj.data;
}
}

// destructor

template <class T>
MyClass<T>::~MyClass()
{
delete data;
}

// stream insertion operator
template <class T>
ostream &operator<<(ostream &s, const MyClass<T> &obj)
{
return s << obj.data;
}


/// the main function

int main()
{
MyClass<char *> test("Hello guys!");

cout << test << endl;

return 0;
}

Alf P. Steinbach

unread,
May 12, 2017, 8:48:19 PM5/12/17
to
On 13-May-17 2:05 AM, alexo wrote:
> Hello all,
> can you find the bug in this code snipped?
> It is a class template I'm trying to write.
> but the linker complains and reminds me I'm a beginner :(

See FAQ item §5.8 "How do I post a question about code that doesn't work
correctly?", e.g. at <url:
http://www.dietmar-kuehl.de/mirror/c++-faq/how-to-post.html#faq-5.8>.

In particular item 7.

It's generally a good idea to check the FAQ before posting. :)
I haven't tried your code, but maybe you need to write

template <class T>
ostream &operator<< <T>(ostream &s, const MyClass<T> &obj)

Have you tried that?


Cheers & hth.,

- Alf

Ben Bacarisse

unread,
May 12, 2017, 9:23:13 PM5/12/17
to
alexo <alessandr...@libero.it> writes:

> Hello all,
> can you find the bug in this code snipped?
> It is a class template I'm trying to write.
> but the linker complains and reminds me I'm a beginner :(
> thank you
>
>
> #include <iostream>
> #include <typeinfo>
> #include <cstring>
>
> using std::string;
> using std::ostream;
>
>
> /// the class' declaration
>
>
> template <class T>
> class MyClass
> {
> T *data;
>
> public:
> MyClass(T);
> MyClass(const MyClass<T> &);
> ~MyClass();
>
> friend ostream & operator<<(ostream &, const MyClass<T> &);

You need

friend ostream & operator<< <>(ostream &, const MyClass<T> &);

here, and operator<< to be previously declared. That requires the class
to be pre-declared (as a template type) above the class definition:

template <class T>class MyClass;
template <class T> ostream & operator<<(ostream &, const MyClass<T> &);

> };
>
>
> /// the class' definition
>
>
> // constructor
>
> template <class T>
> MyClass<T>::MyClass(T val)
> {
> data = new T;
> data = val;

The types are wrong here. I think you meant *data = val;

> }
>
> // copy constructor
>
> template <class T>
> MyClass<T>::MyClass(const MyClass<T> &obj)
> {
> data = new T;
>
> if( typeid(T) == typeid(char *) )
> {
> int len = strlen(obj.data);
> strncpy(data, obj.data, len+1);
> }
> else
> {
> data = obj.data;
> }
> }
>
> // destructor
>
> template <class T>
> MyClass<T>::~MyClass()
> {
> delete data;
> }
>
> // stream insertion operator
> template <class T>
> ostream &operator<<(ostream &s, const MyClass<T> &obj)
> {
> return s << obj.data;

And this prints a pointer. I think you meant s << *obj.data;

> }
>
>
> /// the main function
>
> int main()
> {
> MyClass<char *> test("Hello guys!");

String literals are of type const char * (well, they are arrays but they
convert to pointers) so you can't convert "..." to a char *.

> cout << test << endl;

And here you need std::cout and std::endl;

> return 0;
> }

--
Ben.

alexo

unread,
May 13, 2017, 1:03:53 PM5/13/17
to
Il 13/05/2017 02:48, Alf P. Steinbach ha scritto:
> but the linker complains and reminds me I'm a beginner :(
>
> See FAQ item §5.8 "How do I post a question about code that doesn't work
> correctly?", e.g. at <url:
> http://www.dietmar-kuehl.de/mirror/c++-faq/how-to-post.html#faq-5.8>.
>
> In particular item 7.
>
> It's generally a good idea to check the FAQ before posting. :)
>
>

Here is the output [a bit manipulated to make it more readable]
of the compilation.

warning: friend declaration 'std::ostream& operator<<(std::ostream&,
const MyClass<T>&)' declares a non-template function
[-Wnon-template-friend] (if this is not what you intended, make sure the
function template has already been declared and add <> after the
function name here)

in function 'int main()':
warning: deprecated conversion from string constant to 'char*'
[-Wwrite-strings]

In function `main':
undefined reference to `MyClass<char*>::MyClass(char*)'|

Undefined reference to `operator<<(std::ostream&, MyClass<char*> const&)'

undefined reference to `MyClass<char*>::~MyClass()'|

undefined reference to `MyClass<char*>::~MyClass()'|

error: ld returned 1 exit status|


> I haven't tried your code,

try it please, because I'm going crazy to find the subtle error that
prevents the compilation.

Thank you


alexo

unread,
May 13, 2017, 1:07:30 PM5/13/17
to
Il 13/05/2017 03:23, Ben Bacarisse ha scritto:

>> // constructor
>>
>> template <class T>
>> MyClass<T>::MyClass(T val)
>> {
>> data = new T;
>> data = val;
>
> The types are wrong here. I think you meant *data = val;
>

you are right... :)

>> // stream insertion operator

>> template <class T>
>> ostream &operator<<(ostream &s, const MyClass<T> &obj)
>> {
>> return s << obj.data;
>
> And this prints a pointer. I think you meant s << *obj.data;
>

and you are right again

>>
>>
>> /// the main function
>>
>> int main()
>> {
>> MyClass<char *> test("Hello guys!");
>
> String literals are of type const char * (well, they are arrays but they
> convert to pointers) so you can't convert "..." to a char *.
>
>> cout << test << endl;
>
> And here you need std::cout and std::endl;
>
>> return 0;
>> }

forgotten :)


Alf P. Steinbach

unread,
May 13, 2017, 2:47:06 PM5/13/17
to
OK. Most of those are spurious, unreal errors. The compiler gets
confused due to the real technical errors.

With the /language/ errors fixed it compiles:


---------------------------------------------------------------------
#include <iostream>
#include <typeinfo>
#include <cstring>

using std::string;
using std::ostream;

template <class T>
class MyClass
{
T *data;

public:
MyClass(T);
MyClass(const MyClass<T> &);
~MyClass();


template< class U > //!
friend ostream & operator<<(ostream &, const MyClass<U> &); //!
};


template <class T>
MyClass<T>::MyClass(T val)
{
data = new T;
*data = val; //!
}

template <class T>
MyClass<T>::MyClass(const MyClass<T> &obj)
{
data = new T;

if( typeid(T) == typeid(char *) )
{
int len = strlen(obj.data);
strncpy(data, obj.data, len+1);
}
else
{
data = obj.data;
}
}

template <class T>
MyClass<T>::~MyClass()
{
delete data;
}

template <class T>
ostream &operator<<(ostream &s, const MyClass<T> &obj)
{
return s << obj.data;
}

int main()
{
MyClass<char const*> test("Hello guys!"); //!
using namespace std;
cout << test << endl;
}

---------------------------------------------------------------------

Note that there are still a host of errors in this code, but the
compiler I used, with the options I used, wasn't smart enough to
diagnose them, and isn't required by the standard to diagnose them.

As general advice, instead of dealing with `char const*` and `new` etc.,
just use `std::string` and `std::vector`.

More comfortable, more safe, more easy, can even be faster. ;-)


Cheers!,

- Alf

Kong

unread,
May 14, 2017, 11:24:23 AM5/14/17
to
Can you consult the C++ help file that used ? see Example code for preserve word. But this may not help , for the cracked compliler.

alexo

unread,
May 16, 2017, 3:44:00 PM5/16/17
to
I've simplified the code removing the pointer but the message I get
compiling it is always the same

obj\Release\main.o||In function `main':|
class\main.cpp|13|undefined reference to `MyClass<int>::MyClass(int)'|
class\main.cpp|13|undefined reference to `MyClass<int>::~MyClass()'|
class\main.cpp|13|undefined reference to `MyClass<int>::~MyClass()'|

error: ld returned 1 exit status|

Build failed: 4 error(s), 0 warning(s) (0 minute(s), 0 second(s))

$ errors but the compiler doesn't tell me what they are. It shows only
linker errors.


btw this is the output of the compiler --version command

g++ (tdm-1) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

what is the problem in my code?


#include <iostream>
#include <typeinfo>
#include <cstring>

using std::cout;
using std::endl;

/// the class' declaration



template <class T>
class MyClass
{
T data;

public:
MyClass(T);
MyClass(const MyClass<T> &);
~MyClass();
};


/// the class' definition


// constructor

template <class T>
MyClass<T>::MyClass(T val)
{
data = val;
}

// copy constructor

template <class T>
MyClass<T>::MyClass(const MyClass<T> &obj)
{
if( typeid(T) == typeid(char *) )
{
int len = strlen(obj.data);
strncpy(data, obj.data, len+1);
}
else
{
data = obj.data;
}
}

/// the main function

int main()
{
MyClass<int> test(3);

cout << test.data << endl;

return 0;
}

red floyd

unread,
May 16, 2017, 4:36:55 PM5/16/17
to
I'm not sure why you're getting the linker error on the constructor,
since it seems like you actually did define it, but the linker error
on the destructor is because you only declared it, but didn't define
it.

Paavo Helde

unread,
May 17, 2017, 1:33:01 AM5/17/17
to
On 16.05.2017 22:43, alexo wrote:
> I've simplified the code removing the pointer but the message I get
> compiling it is always the same
>
> obj\Release\main.o||In function `main':|
> class\main.cpp|13|undefined reference to `MyClass<int>::MyClass(int)'|
> class\main.cpp|13|undefined reference to `MyClass<int>::~MyClass()'|
> class\main.cpp|13|undefined reference to `MyClass<int>::~MyClass()'|
>
> error: ld returned 1 exit status|
>
> Build failed: 4 error(s), 0 warning(s) (0 minute(s), 0 second(s))
>
> $ errors but the compiler doesn't tell me what they are. It shows only
> linker errors.

Yes, the 4 errors are the 3 linker error lines plus the fact that linker
returned an error exit status. Do not turn too much attention to the
exact number of them.

However, the error about missing destructor seems to have correct, there
is no destructor defined in the code.
This line does not compile because test.data is private. So there cannot
be any linker errors because the compilation never reaches the linking
stage.

So it appears that the main problem with your code is that the posted
code does not match the posted errors. Maybe you have mixed up the cpp
files on your computer as well?


>
> return 0;
> }
>

alexo

unread,
May 17, 2017, 1:43:15 PM5/17/17
to
Il 17/05/2017 07:32, Paavo Helde ha scritto:

>>
>> /// the main function
>>
>> int main()
>> {
>> MyClass<int> test(3);
>>
>> cout << test.data << endl;
>
> This line does not compile because test.data is private. So there cannot
> be any linker errors because the compilation never reaches the linking
> stage.
> So it appears that the main problem with your code is that the posted
> code does not match the posted errors. Maybe you have mixed up the cpp
> files on your computer as well?

effectively I did it sorry. The version posted is not the one I posted
the output about. But I can assure you I get these messages anytime.
What I want to know is: does my code - (make T data public and try to
compile it) - compile on your machines? Do you get the same linker errors?
These messages appear to me even if I manually define the destructor. I
tried to compile it (the correct .cpp source file) both on a linux (Mint
18.1, g++ version 5.4.0 - CodeLite IDE) and a MS Windows machine (g++
4.9.2 MinGW + Code::Blocks ide) and I still get the same output. So I
don't know if there's a problem with my sintax. Is it correct or not?

thank you

alexo

unread,
May 17, 2017, 1:56:24 PM5/17/17
to
Il 16/05/2017 22:36, red floyd ha scritto:
> On 5/16/2017 12:43 PM, alexo wrote:
>> I've simplified the code removing the pointer but the message I get
>> compiling it is always the same
>>
>> obj\Release\main.o||In function `main':|
>> class\main.cpp|13|undefined reference to `MyClass<int>::MyClass(int)'|
>> class\main.cpp|13|undefined reference to `MyClass<int>::~MyClass()'|
>> class\main.cpp|13|undefined reference to `MyClass<int>::~MyClass()'|
>>
>> error: ld returned 1 exit status|
>>
>> Build failed: 4 error(s), 0 warning(s) (0 minute(s), 0 second(s))
>>
>> $ errors but the compiler doesn't tell me what they are. It shows only
>> linker errors.
>>
>>
>> btw this is the output of the compiler --version command
>>
>> g++ (tdm-1) 4.9.2
>> Copyright (C) 2014 Free Software Foundation, Inc.
>> This is free software; see the source for copying conditions. There
>> is NO
>> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
>> PURPOSE.
>>
>> what is the problem in my code?

[...]

> I'm not sure why you're getting the linker error on the constructor,
> since it seems like you actually did define it, but the linker error
> on the destructor is because you only declared it, but didn't define
> it.

That being linker errors, it seems to me that the compiler fails to
generate the code of the requested function calls.

Paavo Helde

unread,
May 17, 2017, 2:40:07 PM5/17/17
to
It should compile if you define the destructor and make data public. If
it does not, then you introduced some other error. Please post the new
code and matching error messages, we are not psychics here!

So I
> don't know if there's a problem with my sintax. Is it correct or not?

If you get to the linker errors, this means that at least the compiler
was satisfied with your syntax. Whether the code is actually correct and
does what you wanted is another story.



alexo

unread,
May 18, 2017, 7:26:19 AM5/18/17
to
Il 17/05/2017 20:39, Paavo Helde ha scritto:

> It should compile if you define the destructor and make data public. If
> it does not, then you introduced some other error. Please post the new
> code and matching error messages, we are not psychics here!

I thought you were that ; )

>
> So I
>> don't know if there's a problem with my sintax. Is it correct or not?
>
> If you get to the linker errors, this means that at least the compiler
> was satisfied with your syntax. Whether the code is actually correct and
> does what you wanted is another story.

It happened a strange thing.
I put all the code in a single main.cpp file and it compiles, links and
executes correctly.
While having a MyClass.h and MyClass.cpp files whorking with a main
function in a separate file, it gives those strange linker error messages.

here is the correct code:

#include <iostream>
#include <typeinfo>
#include <string>

#include <stdio.h>

using std::cout;
using std::endl;
using std::string;


/// the class' declaration


template <class T>
class MyClass
{
public:
T data;
MyClass();
MyClass(T);
MyClass(const MyClass &);
};


/// the class' definition


// constructor

template <class T>
MyClass<T>::MyClass(T val)
{
data = val;
}

template <class T>
MyClass<T>::MyClass()
{
data = 10;
}

// copy constructor

template <class T>
MyClass<T>::MyClass(const MyClass<T> &obj)
{
if( typeid(T) == typeid(char *) )
{
int len = strlen(obj.data);
strncpy(data, obj.data, len+1);
}
else
{
data = obj.data;
}
}

int main()
{
MyClass<string> test("THREE");

Paavo Helde

unread,
May 18, 2017, 9:20:16 AM5/18/17
to
On 18.05.2017 14:26, alexo wrote:
>
> It happened a strange thing.
> I put all the code in a single main.cpp file and it compiles, links and
> executes correctly.
> While having a MyClass.h and MyClass.cpp files whorking with a main
> function in a separate file, it gives those strange linker error messages.

Seems like https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl





alexo

unread,
May 18, 2017, 1:21:33 PM5/18/17
to
Ok now I can relax my brain...it's not a thing that happens to me only.
And it is not a conceptual error projecting the class.

In the FAQ there is written that this behaviour is "intended" right so
in the standard. I think this way they made things more complex, rather
than simplifying them.
After all if I write a big project with dozens or more source files
expose the code to the user of the class is the oppostite to the concept
of implementation hiding.

Anyway the GURUs made their decisions.

Thank you for having the patience to read my shizophrenic posts.

bye

Paavo Helde

unread,
May 18, 2017, 2:26:08 PM5/18/17
to
They were not happy about that; that's why they added the untested
"export templates" feature into the 1998 standard which was supposed to
solve such issues. Alas, this proved too hard to implement and even if
implemented it did not provide better compilation speeds (as was hoped),
so template export was scraped out from the 2011 standard.

Implementation hiding is actually pretty simple with templates: just put
the template method definitions in a separate file MyClass.tpp or
something, write in the beginning of file

// Implementation details, (c) alexo 2017

and #include it in the end of your MyClass.h file. The ultimate goal of
most users of your class is to know as little about it as possible, so
they will happily skip everything marked "implementation details".



alexo

unread,
May 19, 2017, 9:19:54 AM5/19/17
to
Il 18/05/2017 20:25, Paavo Helde ha scritto:
>
> Implementation hiding is actually pretty simple with templates: just put
> the template method definitions in a separate file MyClass.tpp or
> something, write in the beginning of file
>
> // Implementation details, (c) alexo 2017
>
> and #include it in the end of your MyClass.h file. The ultimate goal of
> most users of your class is to know as little about it as possible, so
> they will happily skip everything marked "implementation details".
>
I'll probably never have the need to hide portions of code, because I'm
a lover of computer programming and I write just stupid things like a
stack, a queue or simply a linked list for didactical personal
purpouses, still learning C++. Those errors allarmed me, but evidently
they were not due to a misunderstanding of some programming principle
rather than to an implementation choice of a language feature.

Every time I was in the need of help I wrote on this newsgroup and I've
always had my question solved. I thank you all.


0 new messages