Use of sstream causing a deleted copy constructor - c++

So I am a CS student working on a project for exception handling (Try/catch). My teacher told us to implement the sstream library so we could use it in a class that outputs a message that includes a passed parameter of type int. For some reason unknown to me, when I use it, or even when I declare a variable of type stringstream, it causes a compile error with error message:
"copy constructor of 'tornadoException' is implicitly deleted because field 'ss' has a deleted copy constructor"
Here is my code. I am at a loss.
main.cpp
#include <iostream>
#include <string>
#include <sstream>
#include "tornadoException.h"
using namespace std;
int main()
{
try{
int tornado = 0;
cout << "Enter distance of tornado: ";
cin >> tornado;
if(tornado > 2){
throw tornadoException(tornado);
}
else{
throw tornadoException();
}
}
catch(tornadoException tornadoObj){
cout << tornadoObj.what();
}
}
tornadoException.cpp
#include <iostream>
#include <string>
#include <sstream>
#include "tornadoException.h"
using namespace std;
tornadoException::tornadoException(){
message = "Tornado: Take cover immediately!";
}
tornadoException::tornadoException(int m){
ss << "Tornado: " << m << "miles away!; and approaching!";
message = ss.str();
}
string tornadoException::what(){
return message;
}
tornadoException.h
#ifndef tornadoException_h
#define tornadoException_h
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class tornadoException{
public:
tornadoException();
tornadoException(int m);
string what();
private:
stringstream ss;
string message;
};
#endif

Alright, figured out the error but I'll leave up this post since I couldn't find the answer anywhere else. The problem was that I declared the stringstream buffer as a private variable in the class. The buffer needs to be declared locally within the function declaration it is being used in, in this case right before the loading of the buffer in the implementation file:
tornadoException::tornadoException(int m){
stringstream ss;
ss << "Tornado: " << m << " miles away!; and approaching!";
message = ss.str();
}

stringstream has a deleted copy constructor, which means that a stringstream object cannot be copied.
Since your tornadoException class has a stringstream variable, this means that your class cannot be copied either.
In your main function, you capture the exception by value, which means that you are copying it into the tornadoObj variable - which is not allowed.
Try changing the line
catch(tornadoException tornadoObj) to catch(tornadoException& tornadoObj) so that you're getting a reference to the exception instead of a copy of it.
This is actually a general rule: An exception shall always be caught by reference, not by copy: Core Guidelines E.15

Related

Linker says a function is already defined if I try to define it in another file (running tests)

I have the following files in a testing project:
Test.cpp:
#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>
#include "PrintOne.cpp"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace PointandVectorCreationTest
{
TEST_CLASS(PointandVectorCreationTest)
{
public:
TEST_METHOD(TestMethod1)
{
std::string expected = "1\n";
std::stringstream buffer;
std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer
int result = printOne();
// When finished, redirect cout to the original buffer
std::cout.rdbuf(sbuf);
std::cout << "std original buffer: \n";
std::cout << buffer.get();
// Test
Assert::AreEqual(expected, buffer.str());
}
};
}
PrintOne.cpp:
#include <iostream>
int printOne() {
std::cout << 1 << std::endl;
return 0;
}
When I try to run this test in Visual Studio, the linker throws the following error:
Error LNK2005 "int __cdecl printOne(void)" (?printOne##YAHXZ) already defined in PrintOne.obj
This error is thrown when linking Test.obj.
I'm not defining printOne anywhere in Test.cpp. In fact, if I just copy the definition of the function to Test.cpp and eliminate the PrintOne.cpp file like so:
Test.cpp:
#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>
int printOne() {
std::cout << 1 << std::endl;
return 0;
}
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace PointandVectorCreationTest
{
TEST_CLASS(PointandVectorCreationTest)
{
public:
TEST_METHOD(TestMethod1)
{
std::string expected = "1\n";
std::stringstream buffer;
std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer
int result = printOne();
// When finished, redirect cout to the original buffer
std::cout.rdbuf(sbuf);
std::cout << "std original buffer: \n";
std::cout << buffer.get();
// Test
Assert::AreEqual(expected, buffer.str());
}
};
}
The test runs just fine. I'd rather avoid writing all the functions I use in the same file I test them, so to me this shouldn't be a solution.
Why does the linker throw this exception? How can I fix this so I can keep my function definitions separate from the testing file?
I'm not defining printOne anywhere in Test.cpp.
Actually, you are, when you #include the source code of PrintOne.cpp into Test.cpp. If you then compile and link both Test.cpp and PrintOne.cpp together, the linker indeed sees 2 definitions of printOne(), one in each .obj file.
For what you are attempting to do, you need to add a .h file that just declares printOne(), and then you can #include that file into both .cpp files, where only one of them defines printOne(), eg:
Test.cpp:
#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>
#include "PrintOne.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace PointandVectorCreationTest
{
TEST_CLASS(PointandVectorCreationTest)
{
public:
TEST_METHOD(TestMethod1)
{
std::string expected = "1\n";
std::stringstream buffer;
std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer
int result = printOne();
// When finished, redirect cout to the original buffer
std::cout.rdbuf(sbuf);
std::cout << "std original buffer: \n";
std::cout << buffer.get();
// Test
Assert::AreEqual(expected, buffer.str());
}
};
}
PrintOne.h
#pragma once
int printOne();
PrintOne.cpp:
#include "PrintOne.h"
#include <iostream>
int printOne() {
std::cout << 1 << std::endl;
return 0;
}
When you have a line like #include "PrintOne.cpp" in your Test.cpp file, then the entire contents of PrintOne.cpp (including the definition of the printOne() function) will be included in Test.cpp's source code; thus, the Test.obj file will contain a definition of the printOne() function.
If you then also have the PrintOne.cpp file included in your project - as it seems from the fact that the linker is referencing a PrintOne.obj module - then there will also be a definition of the printOne() function in that object file, too.
So, you have multiple (though identical) definitions of the function, as signalled by the linker.
To avoid this, replace the inclusion of the PrintOne.cpp source file with one for a header (say #include "PrintOne.h") that provides a declaration (prototype/signature) for the printOne function (The contents of the source file will be added, anyway, if it is part of the project.)
Generally, it is not advisable to #include ... source (cpp) files (though there are some circumstances where it can be useful). Worth reading: When do I need to #include .cpp files?

"no operator >> matches these operands"

I'm a complete noob at C++, and the first problem I am encountering is the following:
no operator >> matches these operands
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "hello world!";
cin >> "hello world!";
}
std::cin needs to write to a variable, but you are passing it a const char[13] string literal instead.
You need to pass it something like a std::string instead:
std::string str;
std::cin >> str;
P.S. This is a good time to a) read compiler messages, b) avoid using namespace std; globally, c) get a good C++ book.

I can't define a string in my C++ code in qt

My code is as follows.
#include "test.h"
#include "string"
#include "iostream"
using namespace std::string::find;
test::test(){
string str ("ffs test ffs");
string str2 ("test");
if (str.find(str2) != std::string::npos) {
std::cout << "found" << "\n";
} else {
std::cout << "not found" << "\n";
}
}
the issue I'm having is this, when trying to define a string in the C++ file qt states "unknown type name 'string'". Also on line 4 my 'import' highlights string as if it doesn't exist, despite it being an option the editor suggests to me while I'm typing it. What am I doing wrong here? Everything I find is to try and fix issues passing stuff to QStrings and nothing related to my issue as far as I can tell. I've tried both types of importing #include <thing> and #include "thing" on all the imports it doesn't seem to make a difference.
Use std::string instead of string.
#include "test.h"
#include <string>
#include <iostream>
test::test(){
std::string str ("ffs test ffs");
std::string str2 ("test");
if (str.find(str2) != std::string::npos) {
std::cout << "found" << "\n";
} else {
str::cout << "not found" << "\n";
}
}
Don't use using namespace (of course in your case, it wasn't a namespace, so that's another error), use <> for system headers.
After inclusion of the appropriate headers iostream, string etc, you can write:
using std::string;
This will bring in only string from the namespace std into your program.
And you can do this if you want to avoid typing std::string everywhere. You can do this for stream objects like cout, cin as well.
using std::cout;
using std::cin;
Use Scope operator :: in Your Code and Access manually to std class
std::string
it will help you !

Why won't C++ let me use a string as a data member in a class?

So I have the following code in a header file named Classes.h:
#ifndef CLASSESS_H
#define CLASSESS_H
class PalindromeCheck
{
private:
string strToCheck;
string copy;
public:
PalindromeCheck(string testSubject) : strToCheck(testSubject) {} //Constructor
void Check()
{
copy = strToCheck; //Copy strToCheck into copy so that once strToCheck has been reversed, it has something to be checked against.
reverse(strToCheck.begin(), strToCheck.end()); //Reverse the string so that it can be checked to see if it is a palindrome.
if (strToCheck == copy)
{
cout << "The string is a palindrome" << endl;
return;
}
else
{
cout << "The string is not a palindrome" << endl;
return;
}
}
};
#endif
And now I have the following code in a source file:
#include <iostream>
#include <string>
#include <algorithm>
#include "Classes.h"
using namespace std;
int main()
{
PalindromeCheck firstCheck("ATOYOTA");
firstCheck.Check();
return 0;
}
When I compiled this code using the Visual C++ Compiler, I got a ton of errors messages that all stemmed from these first four:
'strToCheck': unknown override specifier
missing type specifier - int assumed.
'copy': unknown override specifier
missing type specifier - int assumed.
I tried adding in #include <string> into the header file and recompiled it but it did absolutely nothing. This confuses me because I thought I could use a string as a datatype, but apparently not in a class? It would be great if someone could help me out because I don't know why my code isn't working.
You need to #include <string> in the class header itself.
You also need to either use the std:: namespace (preferable) or also add using namespace std to that header as well (which I strongly discourage).

Declare a string type in a class (C++)

Here is my file.h :
#define MAXCOMPONENTS 20
#include <string>
#include <string.h>
#include <iostream>
class file{
public:
file(char const * filename);
virtual ~file();
void Takeinfocomponents();
void Takeshape();
void Getvalue(int i);
char *Getcomponents();
char *Getcolor();
protected:
private:
char const * filename;
String shape;
int value[MAXCOMPONENTS];
char components[MAXCOMPONENTS];
char color[MAXCOMPONENTS];
};
And my file.cpp :
#include <fstream>
#include <iostream>
#include <string.h>
#include <string>
#include "file.h"
using namespace std;
file::file(char const* filename)
{
cout << "constructor/fichier:" << filename << endl;
ifstream fichier(filename,ios::in);
if(fichier){
this->filename=filename;
fichier.close();
Takeshape();
Takeinfocomponents();
}else{
cout << "File name invalid." << endl;
}
}
file::~file()
{
}
char* file::Getcolor(){
return this->color;
}
char* file::Getcomponents(){
return this->components;
}
void file::Getvalue(int i){
cout << this->value[i] << endl;
}
void file::Takeinfocomponents(){ // pic up name of components, his number and his color
cout << "Takeinfocomponents/fichier:" << filename << endl;
ifstream fichier(this->filename,ios::in);
ifstream stop(this->filename,ios::in);
string line;
int i=0;
getline(fichier,line);
getline(stop,line);
getline(stop,line);
while(line!="/" && i!=99){ // take all informations while the stop signal isn't read
getline(stop,line);
fichier >> this->components[i] >> this->value[i] >> this->color[i];
cout << this->components[i] << this->value[i] << this->color[i] << endl;
i++;
}
fichier.close();
}
void file::Takeshape(){ // pic up the shape in .txt
cout << "Takeshape" << endl;
fstream fichier(this->filename,ios::in);
string shape;
fichier >> shape;
this->shape=shape;
fichier.close();
}
This is a part of a larger programm who make graphic from informations ( from the .txt ), this part is use to pic up informations from the .txt.
The problem come from the declaration of the :
String shape;
He told me that string is not a name type. I've tried with a small "s" :
string shape;
But this ain't working.
I've the impression that i miss a very small things that could unlock my problem.
Thx for help.
Notabene : I'm french and my english is not this good, please answer like i was a little child ahah !
You have to explicitly state the namespace:
std::string shape;
You shouldn't pollute the namespace in the headers, so using namespace std is not an option here.
See also the question about namespace pollution. If you just need strings, prefer to use
using std::string;
in the cpp file.
C++ uses the concept of a namespace. A namespace is used to group types, variables, etc. together in a meaningful way, regardless of the number of header files those types or variables are spread across.
In this example, the string type is inside the std namespace. std is short for Standard Template Library, and it is the namespace that most of C++'s library classes, etc. are stored in.
The correct way of accessing type inside a namespace is namespace::type, so the correct way of accessing the string type inside the std namespace is std::string. You can also write using namespace std to access the types in std without having to write std:: each time, but doing this in a global scope is a bad idea, because it pollutes the global namespace.
In the code you posted, string shape; appears before using namespace std, as the #include "file.h" appears before it. Therefore, it won't take effect.
To be able to use the string class and create string objects, you need to include...
#include <string>
... at the top of your header files.
You do not need...
#include <string.h>
The string class, like all STL classes, is part of the std namespace. If you do not want to write std:: before every class name, you can simply state...
using namespace std;
... at the top of your header files so that instead of...
std::string shape;
... you can simply use...
string shape;