A strange behavior about constructors in C++ - c++

I show you the code directly.
#include <iostream>
#include <stdio.h>
class A {
public:
A(const std::string& name){
std::string aname = "HAHA_" + name;
std::cout << aname << std::endl;
}
~A(){
std::cout << "Done." << std::endl;
}
};
int main() {
size_t len = 5;
char szTmp[30] ={0};
snprintf(szTmp,sizeof(szTmp),"Getlist_V2_%zd",len);
A a(std::string(szTmp));
return 0;
}
The expected results are as follows:
HAHA_Getlist_V2_5
Done.
But It outputs nothing at all. When I replace A a(std::string(szTmp)); with
A a(szTmp); ,erverything is ok. It confused me for a long time.

A a(std::string(szTmp));
This is a function declaration, believe it or not! So, no A is constructed.
Instead, write this:
A a{std::string(szTmp)};
Or, since an implicit conversion to std::string exists, either of the following will suffice:
A a{szTmp};
A a(szTmp);

Related

Weird behavior with OOP and string pointers

Here's my code:
#include <iostream>
#include <string>
class Human
{
public:
std::string * name = new std::string();
void introduce();
};
void Human::introduce()
{
std::cout << "Hello, my name is " << Human::name << std::endl;
}
int main()
{
Human * martha;
martha->name = new std::string("Martha");
martha->introduce();
return 0;
}
Well, it's supposed to print a message out like:
"Hello, my name is Martha" but it doesn't print neither the "Hello, my name is" string or the "Martha" name. Why does it occur?
The fix is simple and is to completely remove all pointers; see the code below. There are a number of issues with your code that I could address in detail, including memory leaks, uninitialized variables, and general misuse of pointers, but it seems that you're possibly coming from a different language background and should spend time learning good practice and the important semantics and idioms in modern C++ from a good C++ book.
#include <iostream>
#include <string>
class Human
{
public:
std::string name;
void introduce();
};
void Human::introduce()
{
std::cout << "Hello, my name is " << name << std::endl;
}
int main()
{
Human martha;
martha.name = "Martha";
martha.introduce();
return 0;
}
Few modifications are required to the code.
Updated code along with the comments to the change made are included below.
#include <iostream>
#include <string>
class Human
{
public:
//Removed pointer to a string
//Cannot have an instantiation inside class declaration
//std::string * name = new std::string();
//Instead have a string member variable
std::string name;
void introduce();
};
void Human::introduce()
{
//Human::name not required this is a member function
//of the same class
std::cout << "Hello, my name is " << name << std::endl;
}
int main()
{
Human *martha = new Human();
//Assign a constant string to string member variable
martha->name = "Martha";
martha->introduce();
return 0;
}
As suggested by #alter igel - The Definitive C++ Book Guide and List would be a good place to start.
#include <iostream>
#include <string>
class Human {
public:
void Human(std::string* n) { name = n; }
void introduce();
private:
std::string* name;
};
void Human::introduce() {
std::cout << "Hello, my name is " << name << std::endl;
}
int main() {
Human* martha = new Human(new std:string("Martha"));
martha->introduce();
return 0;
}
Try that. The difference is that you don't initialise the variable in the class definition, and you initialise the name with the constructor. You can split the method definition out into it's own section, but it's only one line and is fine being inside the class definition.

Is it possible to call a method from an instance that doesn't exist?

The code I'm working on :
I had the following code (with an error about the index in main.cpp) :
Sample.hpp :
#ifndef SAMPLE_HPP
# define SAMPLE_HPP
# include <iostream>
# include <string>
class Sample{
public:
Sample(void);
~Sample(void);
void tellname(void) const;
private:
std::string _name;
};
#endif
Sample.cpp :
#include <iostream>
#include "Sample.hpp"
Sample::Sample(void){
this->_name = "testname";
return;
};
Sample::~Sample(void){
return;
}
void Sample::tellname(void) const{
std::cout << "Name : " << this->_name << std::endl;
return;
}
main.cpp
#include "Sample.hpp"
int main(void){
int i;
Sample *test;
test = new Sample[4];
i = 0;
while (i++ < 4) // I know : i++; shouldn't be here
test[i].tellname();
delete [] test;
return 0;
}
If I compile this I get the following output :
Name : testname
Name : testname
Name : testname
Name :
My question is :
About the last line, it calls a method (void Sample::tellname(void)) but from an instance that is not in the range of the table (test[4] doesn't exist).
However, it still calls tellname() even the instance it calls it from doesn't exist. It just considers its _name field being empty.
How is this possible?
It's simply undefined behavior, something C++ imposes no requirements on so "anything could happen". What you're seeing is just a coincidence and worthless to reason about: next time you run it could crash, display nyan cat and so on.
It sounds like you are wondering why the function is called. In memory, structs do not contain the functions inside them. Instead, one copy of the functions are placed somewhere in the executable. So when you are calling test[4].tellname() what is really happening is: The address test + (4 * sizeof(Sample)) is passed to the function tellname(). The value at that address is undefined.
Here is an example to give you an idea of what is going on:
#include <iostream>
struct astruct {
int i = 0;
void prnt()
{
std::cout << i << '\n';
}
};
struct bstruct {
int y = 100;
};
int main()
{
bstruct b;
((astruct*)&b)->prnt();
getchar();
return 0;
}
Here prnt() is behind the scenes being passed the address of bstruct and treats it like the address of an astruct, since the first value in bstruct is 100, it prints 100. You can even simplify it to this:
#include <iostream>
struct astruct {
int i = 0;
void prnt()
{
std::cout << i << '\n';
}
};
int y = 100;
int main()
{
((astruct*)&y)->prnt();
getchar();
return 0;
}
i goes from 1 to 4 include, since tellname is const, test[4].tellname() is Sample::tellname with Sample being an undefined structure so "Name :" is rightfully printed then the memory in test[4]._name is printed and luckily the memory pointed by test[4]._name* is non null and is even a end string char.
So yeah you are lucky.

How to differentiate between char literal and unsigned int as a parameter for a constructor

My Code has 2 different constructors, one with just an unsigned as a parameter and another one with a char and an unsigned, where the unsigned has a default value.
Myclass::Myclass(unsigned);
Myclass::Myclass(const char, unsigned = 1);
The problem ist that when I try the following:
Myclass a = 'A';
the constructor with only the unsigned as parameter is called(in this example with 65)
How can i have the second constructor be called in this case?
I also dont want values from 0-255 to only be interpreted as Ascii values.
EDIT:
Example code that displays error:
Header:
#ifndef Myclass_H_
#define Myclass_H_
class Myclass {
public:
Myclass(unsigned int = 10);
Myclass(const char*);
Myclass(char , unsigned int= 10);
Myclass(const Myclass&);
virtual ~Myclass();
};
#endif /* Myclass_H_ */
Class body:
#include "Myclass.h"
#include <iostream>
using namespace std;
Myclass::Myclass(unsigned int)
{
cout << "unsigned" << endl;
}
Myclass::Myclass(const char*)
{
cout << "pointer" << endl;
}
Myclass::Myclass(char , unsigned int)
{
cout << "char" << endl;
}
Myclass::Myclass(const Myclass&)
{
cout << "copy" << endl;
}
Myclass::~Myclass(){}
int main()
{
Myclass a = 'A';
return 0;
}
displays "unsigned" in console.
I'm not able to duplicate the problem you claim. I did a quick check with the following test code:
#include <iostream>
struct foo {
foo(const char, unsigned = 1) { std::cout << "Foo(char, unsigned)"; }
foo(unsigned) {
std::cout << "Foo(unsigned)";
}
};
int main() {
foo f = 'A';
}
...and with the compilers I have handy (VC++ 2013, VC++ 2015, g++ 4.8, g++5.2), foo(char, unsigned) is always the one that's chosen (which is as I'd expect).
What compiler are you using that selects the other overload for this input? I'd expect this from truly ancient compilers (that followed the C rule, where a character literal has type int rather than type char) but those have been obsolete for decades.
Make the unsigned constructor explicit, something like:
Myclass {
explicit Myclass (unsigned);
// ...
}

destructor ignore string assignment

I have created a program in C++ for a class, and one of the requirements is to output a string when certain parts of the program have been called. For most of these I have simply assigned a string to a member variable and then outputted that variable. I wanted to know is it possible for me to assign the string in a destructor and then output that string? When I try it, it outputs nothing.
ie:
Class
private:
string output;
~Class {
output = "destructor has fired!";
}
int main(){
cout << class.message;
}
This is pseudocode so please ignore syntax mistakes/missing pieces.
It certainly is possible to output a message in the destructor, to know that it has fired, and one way to do it is this...
#include <iostream>
#include <string>
using namespace std;
class C{
string output; // by default private
public:
C(){}
~C() { cout << output << endl; }
void setString(const string& s) {
output = s;
}
};
int main()
{
{
C s;
s.setString("Destructor has fired");
}
return 0;
}
If I understand your question right, this is what you are expected to do. Note: no member variable, direct calls to std::cout.
#include <iostream>
#include <string>
using namespace std;
class C{
public:
C() {
cout << "C ctor" << endl;
}
~C() {
cout << "C dtor" << endl;
}
};
int main()
{
{
C s;
}
return 0;
}

How to reconstruct non-pointer class member containing vector?

I'm facing a weird issue : I can't reset (destruct and construct) properly an attribute containing a vector. It causes a segmentation fault when trying to access the vector.
Here is my code (witten in C++11). I think I simplified it the most possible to underscore the issue, but I might be wrong, sorry about that.
The goal would be to print two times two different (random) vectors. The first vector is working well, the second is completely failing for an unknown reason.
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <vector>
class A
{
std::vector<int> n;
public :
A();
std::string toString() const;
};
A::A()
{
for (int i = 0; i < 10; i++)
n.push_back(std::rand()%10);
}
std::string A::toString() const
{
for (auto i : n)
std::cout << i << ' ';
std::cout << std::endl;
}
class B
{
A a;
public :
void resetA();
A getA() const;
};
void B::resetA()
{
a = A();
}
A B::getA() const
{
return a;
}
int main()
{
srand(time(NULL));
B b;
std::cout << b.getA().toString();
b.resetA();
std::cout << b.getA().toString();
return EXIT_SUCCESS;
}
For some reason, I would like to avoid pointers and dynamic allocation as far as possible. It would fit less with my UML conception.
Moreover, this code is working well when using simple int (no vectors).
Thank you.
Your toString() doesn't return anything, so your program has Undefined Behaviour (and, in practice, returns random garbage which is most certainly not a valid std::string object).
Perhaps you wanted to use a string stream instead?
#include <sstream>
// ...
std::string A::toString() const
{
std::ostringstream s;
for (auto i : n)
s << i << ' ';
s << '\n';
return s.str();
}
Live example.
Generally, it's a good idea to compile with as many warnings turned on as possible. This would certainly have been reported as a warning then. For this particular warning (no-void function not returning anything), I strongly suggest treating it as an error.