C++ class constructor clears map - c++

My first constructor edits a member std::map and then calls another constructor. At the end of the first constructor the size of the map is 2, and at the start of the second constructor it's 0. What is causing this?
Here is my header file:
// Test.h
#include <map>
#include <string>
class Test
{
public:
Test(std::string name, int age);
private:
Test();
std::map<std::string, int> myMap_;
}
And here is my code:
// Test.cpp
#include "test.h"
Test::Test()
{
std::cout << myMap_.size() << std::endl; // Outputs 0
}
Test::Test(std::string name, int age)
{
myMap_.insert(name, age);
myMap_.insert("test", 6);
std::cout << myMap_.size() << std::endl; // Outputs 2
Test();
}
EDIT:
And here is my main function:
#include "test.h"
int main()
{
Test t("yo", 4);
return 0;
}

The second constructor inserts 2 elements. So the size is 2.
The first constructor inserts no elements. So the size is 0.
I guess maybe you expect Test(); inside the second constructor to "call the other constructor" for the same object. However this does not happen. Constructors are different to regular functions.
The code Test(); actually means to create a temporary object of type Test, which is initialized by calling the default constructor. Then that object is destroyed immediately, since it was temporary.
Constructors have no name, as far as name lookup is concerned, it's not possible to call them like regular functions. Instead they are invoked when you give the syntax to create an object.
If you want to have some common code that is shared by multiple constructors; you could either put that code in a function that is called by the multiple constructors, or use the delegating constructors feature. In the latter case, the delegation must happen before any statements inside the constructor body are executed.

You are not actually calling the constructor on the same object but create a temporary new one, which then has no name. See it as the same as this:
Test::Test(std::string name, int age)
{
myMap_.insert(name, age);
myMap_.insert("test", 6);
std::cout << myMap_.size() << std::endl; // Outputs 2
Test other = Test(); //you create a new object here
}
In C++11 you can do something like you want to do with this (this is called constructor delegation):
Test::Test(std::string name, int age)
:Test()
{
myMap_.insert(name, age);
myMap_.insert("test", 6);
std::cout << myMap_.size() << std::endl;
}
The difference here though is the Test() constructor will be called before the insert operations on the map.

You are creating two instances of a Test.
The first instance of a Test, which is constructed with the name and age, inserts elements into its myMap_ but the second instance does not.
When you call Test() in the Test(name, age) constructor it is creating a second instance of Test locally using the Test() constructor which does not insert into the map. This second instance would then be almost immediately destroyed (as it is not assigned to anything).
I think you are attempting to use two constructors on the same object, but that is only done for inheriting objects, where each derivation needs to call its own constructor and call its base.
You could create a function and call that instead:
// Test.h
#include <map>
#include <string>
class Test
{
public:
Test(std::string name, int age);
void OutputSize();
private:
Test();
std::map<std::string, int> myMap_;
}
Test::Test(std::string name, int age)
{
myMap_.insert(name, age);
myMap_.insert("test", 6);
OutputSize();
}
void Test::OutputName()
{
std::cout << myMap_.size() << std::endl; // Outputs 2
}

Related

vector of threads called from inside a class function

I am trying to do something similar to the last code in this
In the code however you see that
vec_thr.emplace_back(&Test::testme, std::move(t1), std::cref(str)); is called inside the main function.
I would like to do that from a member function of the object Test.
So I did
#include <thread>
#include <string>
#include <vector>
#include <iostream>
class Test
{
private:
public:
void testme(const std::string& _str)
{
std::cout << "Hello " + _str << std::endl;
}
void testFurther(const std::string& _str){
std::vector<std::thread> vec_thr;
// pass the constructor parameters you would have passed to std::thread
// to the emplace_back() function - they are forwarded to the thread that
// is constructed "in place" inside the vector
for(int i=0;i<2;i++){
//HERE I am trying how to write this correctly trying the following:
// vec_thr.emplace_back(&Test::testme, std::move(t1), std::cref(str));
vec_thr.emplace_back(testme, std::move(this), std::cref(_str));
// vec_thr.emplace_back(testme, std::cref(_str));
}
// Don't forget to join all your threads to make sure
// they complete before moving on/exiting
for(auto& t: vec_thr)
t.join();
}
};
int main()
{
const std::string str = "there";
Test t1/*, t2*/;
t1.testFurther(str);
}
However it is not working. I got the error message
error: invalid use of non-static member function
Is there a way to be able to do this.
I want to do the exact same thing that was done originally from the main function
It seems I have solve the problem by changing the class Test function testFurther to
void testFurther(const std::string& _str){
std::vector<std::thread> vec_thr;
// pass the constructor parameters you would have passed to std::thread
// to the emplace_back() function - they are forwarded to the thread that
// is constructed "in place" inside the vector
for(int i=0;i<2;i++){
// vec_thr.emplace_back(&Test::testme, std::move(t1), std::cref(str));
// vec_thr.emplace_back(testme, std::move(this), std::cref(_str));
// vec_thr.emplace_back(&testme, this, std::cref(_str)); // ISO forbid taking the address of an unqualified or parenthesized non-static member function
vec_thr.emplace_back(&Test::testme, this, std::cref(_str)); //THIS WORKS
// vec_thr.emplace_back(testme, std::cref(_str));
}
// Don't forget to join all your threads to make sure
// they complete before moving on/exiting
for(auto& t: vec_thr)
t.join();
}
with this it seems to be working well.
I just wonder why I have to use &Test::testme since Test is the name of the class not of an object instance

Why does calling an overloaded constructor cause a call of the default constructor?

My C++ Programm always calls too more constructors than i intended to. It should create an edge, which then automatically creates two nodes by the string-input of the overloaded edge-constructor.
But it first calls the default-constructor of the node objects and then the overloaded self-defined constructor. The destructors do not delete the default nodes immediately. That causes an error in my program.
The problem is that the program should count the amount of objects and allocate an appropriate ID related to the amount of objects.
Compiler-Output
Default-Constructor
Default-Constructor
Overload-Constructor
ID: 1 numInstances: 2
Destructor
Overload-Constructor
ID: 2 numInstances: 1
Destructor
Edge: -> Node_0002
Destructor
Destructor
Program ended with exit code: 0
Here is a snippet for you to see the code which most likely causes the error:
main.cpp
int main() {
Edge e1 = Edge("1", "2");
std::cout << "Edge: " << e1.toString() << endl;
return 0;
}
node.hpp
double Node::numInstances = 0;
Node::Node()
{
numInstances++;
cout << "Default-Constructor" << endl;
double idNumber = numInstances;
m_id = setUpIdString(idNumber);
}
Node::Node(string id)
{
double idNumber = getNumberFromString(id);
cout << "Overload-Constructor" << endl;
cout << "ID: " << idNumber << " numInstances: " << numInstances << endl;
if (idNumber > numInstances) {
numInstances++;
m_id = setUpIdString(idNumber);
}
}
Node::~Node()
{
numInstances--;
cout << "Destructor" << endl;
}
edge.cpp
Edge::Edge(string src, string dst)
{
m_srcNode = Node(src);
m_dstNode = Node(dst);
}
EDIT:
node.hpp
class Node
{
public:
Node();
Node(string id);
~Node();
string getId();
private:
string m_id;
static double numInstances;
};
edge.hpp
class Edge
{
public:
Edge(Node& rSrc, Node& rDst);
Edge(string src, string dst);
string toString();
Node& getSrcNode();
Node& getDstNode();
private:
Node m_srcNode;
Node m_dstNode;
};
A constructor is not like other functions in C++. A constructor's job is to initialize an object. In order to ensure the object gets initialized in a sensible way, all of the member objects (and base objects) need to be initialized. *This happens before the opening brace of the constructor body, so that everything is in a sensible state when you're in the constructor body.
To make sure this happens in the way you want, you can use an initializer list (note that this term also refers to something else when initializing various containers; if you've heard the term before in relation to that, it's not what I'm discussing here). After the function signature, you put a colon, followed by each member of your class (in the same order they're declared in the class) and how you want to initialize it. For example, if you have the following struct
struct A {
int i;
char c;
std::string s;
A();
};
you can declare define your constructor as
A::A() : i{17}, c{'q'}, s{"Hello, mrb! Welcome to Stack Overflow"}
{
// Nothing to do in the body of the constructor
}
That way, an A object's members are initialized to 17, 'q', and a greeting before the start of the function, and are not initialized any other way.
Since you do not do this, the compiler instead uses the default constructor for the nodes. You then create other nodes inside the constructor body, and assign them to the nodes in your class.
m_srcNode = Node(src);
m_dstNode = Node(dst);
Here, the two objects are first constructed with default constructor, then the overloaded constructed is called with Node(src) and Node(dst). After that, the implicitly defined copy assigner is called to assign the temporary objects to m_srcNode and m_dstNode. Finally the temporary objects are destroyed.
If you want to avoid extra constructor calls, you can write a member initializer list:
Edge::Edge(string src, string dst) : m_srcNode(src), m_dstNode(dst) {}

C++ what happens when function returns vector<shared_ptr<>>?

I have the following code:
#include <iostream>
#include <memory>
#include <vector>
class Test
{
public:
Test() {}
~Test() { std::cerr << "Delete\n"; }
};
std::vector<std::shared_ptr<Test>> makeList()
{
std::vector<std::shared_ptr<Test>> list;
list.push_back(std::make_shared<Test>(Test()));
return std::move(list);
}
int main(int argc ,char **argv)
{
std::vector<std::shared_ptr<Test>> list;
std::cerr << "Before\n";
list = makeList();
std::cerr << "After\n";
return 0;
}
Which I compile with:
clang++ -std=c++14 -o ptr ptr.cpp
The output is:
Before
Delete
After
Delete
My question is: why is there an object being deleted in the makeList function? My assumption was that the list from the function would be moved into list from main and that therefore no object would be deleted/recreated in the process?
Can this be avoided (as obviously this code is not optimum)?
2 Changes:
std::vector<std::shared_ptr<Test>> makeList()
{
std::vector<std::shared_ptr<Test>> list;
// make_shared does not need a copy of an object, just constructor arguments
list.push_back(std::make_shared<Test>());
// return std::move(list) will defeat RVO. Never do that.
return list;
}
So, the important part is :
list.push_back(std::make_shared<Test>(Test()));
->
list.push_back(std::make_shared<Test>());
Just for clarification because I had the same today, and I had trouble seeing the difference.
list.push_back(std::make_shared<Test>(Test()));
Here temporary is created with Test(). Then copy c-tor for Test is invoked and temporary is destroyed. It is the first destructor call.
The second destructor call appears in the end of the program when list is destroyed.
The right form to avoid temporary creation is:
list.push_back(std::make_shared<Test>());
Besides you shouldn't use std::move returning the value because compiler cannot apply Return value optimisation in such case.
The line list.push_back(std::make_shared<Test>(Test())); makes a temporary Test and then moves it into the actual Test constructed by std::make_shared<T>. This temporary is then destroyed.
std::make_shared<T> requires the arguments to be used in construction of T. For a default constructed T simply provide no arguments.
The correct use, in this case, is this:
list.push_back(std::make_shared<Test>());

using a constructor to initialise a string pointer

i am having trouble with my code. I am abit stumped.
I have a data member which is a pointer to a string type.
I use the constructor as a defualt initialer to this pointer, then when I call an object in the main function the intialised pointer to points to the memory address where the string is stored and prints the contents. That is what is supposed to happen, but I can't get the program to work. May somebody please tell me where I am going wrong?
#include<iostream>
#include<string>
using namespace std;
class NoName{
public:
NoName(string &sName("Alice In Wonderland") ){};
private:
string *pstring;
};
int main(){
//the constructor will be automatically called here once a object is created
// and the string "Alice in Wonderland" will appear on the screen
return 0;
}
Just simply use a std::string member and initialize it in Member initializer list:
private:
string mstring;
public:
NoName():mstring("Alice In Wonderland"){}
You could also let the constructor take in a parameter instead of hardcoding the string and let the user pass the string at run-time:
NoName(std::string str):mstring(str){}
You do not need a pointer. By using a pointer to std::string You nullify the advantages of implicit manual memory management offered by std::string.
If you really need to store a pointer for some reason, then there are some points to remember:
Pointers are initialized like new Class
Prefer to initialize class members in the member initializer list
Any time you write the word new think about where you're going to write delete. (In this case it goes in the destructor.
Rule of Three: If you need a destructor (you do, because of delete), then you also need a copy constructor and copy assignment operator.
This is one way your code could look: http://ideone.com/21yGgC
#include<iostream>
#include<string>
using std::cout; using std::endl;
using std::string;
class NoName
{
public:
NoName(string sName = "Alice In Wonderland") :
pstring(new string(sName))
{
cout << "ctor - " << *pstring << endl;
}
NoName(const NoName& rhs) :
pstring(new string(*rhs.pstring))
{
cout << "Copy ctor - " << *pstring << endl;
}
NoName& operator=(const NoName& rhs)
{
*pstring = *rhs.pstring;
cout << "Copy assignment operator - " << *pstring << endl;
return *this;
}
~NoName()
{
cout << "dtor, my name was " << *pstring << endl;
delete pstring;
}
private:
string *pstring;
};
.
int main()
{
NoName m, n("Another name");
NoName o(m);
o = n;
return 0;
}
Notice how much easier it is if you don't use the unnecessary pointer:
class Better
{
public:
Better(string sName = "Alice In Wonderland") :
m_string(sName)
{
}
private:
string m_string;
};
Because you don't need the custom destructor, you also don't need the copy constructor or copy assigment operator either. Much easier!
You're not using the constructor properly. First of all, you create this reference parameter and try to initialize it to a string object (that's asking for problems). Second, your constructor never actually does anything.
You need to call new on your pointer, dereference it and give the data pointed to a value, output the dereferenced value with std::cout and then clean the memory up with delete in the destructor (or in this case, you can do it after you use cout if you're not planning on using that string again. But do it in the destructor if you need it still).
Assuming you're doing this for a class, your textbook should tell you how to do these things.
EDIT: this is also not the default-constructor. I changed your tag to match appropriately.

In an STL Map of structs, why does the "[ ]" operator cause the struct's dtor to be invoked 2 extra times?

I've created a simple test case exhibiting a strange behavior I've noticed in a larger code base I'm working on. This test case is below. I'm relying on the STL Map's "[ ]" operator to create a pointer to a struct in a map of such structs. In the test case below, the line...
TestStruct *thisTestStruct = &testStructMap["test"];
...gets me the pointer (and creates a new entry in the map). The weird thing I've noticed is that this line not only causes a new entry in the map to be created (because of the "[ ]" operator), but for some reason it causes the struct's destructor to be called two extra times. I'm obviously missing something - any help is much appreciated!
Thanks!
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct TestStruct;
int main (int argc, char * const argv[]) {
map<string, TestStruct> testStructMap;
std::cout << "Marker One\n";
//why does this line cause "~TestStruct()" to be invoked twice?
TestStruct *thisTestStruct = &testStructMap["test"];
std::cout << "Marker Two\n";
return 0;
}
struct TestStruct{
TestStruct(){
std::cout << "TestStruct Constructor!\n";
}
~TestStruct(){
std::cout << "TestStruct Destructor!\n";
}
};
the code above outputs the following...
/*
Marker One
TestStruct Constructor! //makes sense
TestStruct Destructor! //<---why?
TestStruct Destructor! //<---god why?
Marker Two
TestStruct Destructor! //makes sense
*/
...but I don't understand what causes the first two invocations of TestStruct's destructor?
(I think the last destructor invocation makes sense because testStructMap is going out of scope.)
The functionality of std::map<>::operator[] is equivalent to
(*((std::map<>::insert(std::make_pair(x, T()))).first)).second
expression, as specified in the language specification. This, as you can see, involves default-constructing a temporary object of type T, copying it into a std::pair object, which is later copied (again) into the new element of the map (assuming it wasn't there already). Obviously, this will produce a few intermediate T objects. Destruction of these intermediate objects is what you observe in your experiment. You miss their construction, since you don't generate any feedback from copy-constructor of your class.
The exact number of intermediate objects might depend on compiler optimization capabilities, so the results may vary.
You have some unseen copies being made:
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct TestStruct;
int main (int argc, char * const argv[]) {
map<string, TestStruct> testStructMap;
std::cout << "Marker One\n";
//why does this line cause "~TestStruct()" to be invoked twice?
TestStruct *thisTestStruct = &testStructMap["test"];
std::cout << "Marker Two\n";
return 0;
}
struct TestStruct{
TestStruct(){
std::cout << "TestStruct Constructor!\n";
}
TestStruct( TestStruct const& other) {
std::cout << "TestStruct copy Constructor!\n";
}
TestStruct& operator=( TestStruct const& rhs) {
std::cout << "TestStruct copy assignment!\n";
}
~TestStruct(){
std::cout << "TestStruct Destructor!\n";
}
};
Results in:
Marker One
TestStruct Constructor!
TestStruct copy Constructor!
TestStruct copy Constructor!
TestStruct Destructor!
TestStruct Destructor!
Marker Two
TestStruct Destructor!
add the following to TestStruct's interface:
TestStruct(const TestStruct& other) {
std::cout << "TestStruct Copy Constructor!\n";
}
Your two mysterious destructor calls are probably paired with copy constructor calls going on somewhere within the std::map. For example, it's conceivable that operator[] default-constructs a temporary TestStruct object, and then copy-constructs it into the proper location in the map. The reason that there are two destructor calls (and thus probably two copy constructor calls) is implementation-specific, and will depend on your compiler and standard library implementation.
operator[] inserts to the map if there is not already an element there.
What you are missing is output for the compiler-supplied copy constructor in your TestStruct, which is used during container housekeeping. Add that output, and it should all make more sense.
EDIT: Andrey's answer prompted me to take a look at the source in Microsoft VC++ 10's <map>, which is something you could also do to follow this through in all its gory detail. You can see the insert() call to which he refers.
mapped_type& operator[](const key_type& _Keyval)
{ // find element matching _Keyval or insert with default mapped
iterator _Where = this->lower_bound(_Keyval);
if (_Where == this->end()
|| this->comp(_Keyval, this->_Key(_Where._Mynode())))
_Where = this->insert(_Where,
value_type(_Keyval, mapped_type()));
return ((*_Where).second);
}
so the lesson is - dont put structs in a map if you care about their lifecycles. Use pointers, or even better shared_ptrs to them
You can check it out through this more simple code.
#include <iostream>
#include <map>
using namespace std;
class AA
{
public:
AA() { cout << "default const" << endl; }
AA(int a):x(a) { cout << "user const" << endl; }
AA(const AA& a) { cout << "default copy const" << endl; }
~AA() { cout << "dest" << endl; }
private:
int x;
};
int main ()
{
AA o1(1);
std::map<char,AA> mymap;
mymap['x']=o1; // (1)
return 0;
}
The below result shows that (1) line code above makes (1 default const) and (2 default copy const) calls.
user const
default const // here
default copy const // here
default copy const // here
dest
dest
dest
dest