When switching compilers my old'n trusted throw code (example below) fails. I'm guessing that it is the err variable scope that is the problem? What happens is that when trying to access the string part of err it has been deallocated. What would be a better way of doing something like this using a custom exception class?
if (someErrorHappend)
{
std::stringstream err;
err << "Some error #" << GetLastError() << ".";
throw SomeCustomException("MyClass", "MyFunc", err.str().c_str());
}
c_str is a non-owning pointer, so you shouldn't pass it to the constructor that will retain it directly.
To fix the problem, simply adjust the constructor SomeCustomException to accept a std::string instead of a char *. The char * will be converted to a string, which is an owning object.
In the future, you can migrate code by removing the c_str() call and leaving only err.str(). The compiler will apply C++11 move semantics to remove one copy operation.
Don't worry about running out of memory. The stringstream code is already allocating on the heap for its internal string, and there's no difference between that and the exception constructor — both run before the throw, and if you ran out of memory beforehand, you should already be in an exception handling state anyway.
Related
What will happen with array1 after I return it? Will it delete itself or will the space be inaccessible? How do I delete[] it?
char* ToCharArray() {
stringstream COUT;
COUT << *day<< "." << *month<< "." << *year<< " " << *hours<< *minutes;
string temp = COUT.str();
int vel = strlen(temp.size) + 1;
char *array1= new char[vel];
strcpy_s(array1, vel, temp.c_str());
return array1;
}
You delete it as you usually delete arrays in C++: with delete[]:
const char* p = ToCharArray();
// ...
delete[] p;
However, note, that the second part of ToCharArray() is pointless. You might return std::string and avoid possible memory leaks:
std::string ToCharArray() {
stringstream COUT;
COUT << *day<< "." << *month<< "." << *year<< " " << *hours<< *minutes;
return COUT.str();
}
In modern C++, it's best to avoid raw new/new[] and delete/delete[] as much as possible in favor of using standard container classes and smart pointers, and if you do have a need for manual memory management then you should try to encapsulate that as much as possible into a container class. And with C++17, you usually shouldn't even need raw pointers - if you have a pointer that you don't own, you can annotate that fact by using std::observer_ptr<T>. In particular, smart pointer types can be used to annotate lifetime expectations; for example, if a function returns a pointer to something it expects the caller to delete when it's done with it, it should return a std::unique_ptr<T>. Similarly, if a function expects to take unique ownership of an object being passed in by pointer and be able to free the memory when it's done, then it should take that argument as a std::unique_ptr<T>. The given function violates this design principle.
However, there will certainly be times when you'll want to use a third-party library which doesn't follow these design principles, and which you don't want to (or can't) edit the source code to. In those cases, what I like to do is to create smart pointers as soon as possible after getting return values from such API functions; this way, I get the maximum benefit out of following the modern C++ idioms outlined above for my code. In this case, that would look like:
std::unique_ptr<char[]> res { ToCharArray() };
Then when this object goes out of scope, the compiler will generate the code to free the memory for you. (Even if something between this line and the end of the containing block ends up throwing an exception which is not caught in that block.)
Similarly, in the case of a function expecting to take ownership of a pointer, I keep it in the unique_ptr<T> as long as possible, then pass p.release() as that argument of the function.
If this is a function which you tend to use often, it might help to create a modern C++ wrapper around the legacy C++ API:
inline std::unique_ptr<char[]> wrap_ToCharArray() {
return std::unique_ptr<char[]> { ToCharArray() };
}
This has benefits such as better exception safety for an expression like f(wrap_ToCharArray(), wrap_ToCharArray()). (Look up the rationale for std::make_unique if you are interested in the details of why this has better exception safety than f(std::unique_ptr<char[]> { ToCharArray() }, std::unique_ptr<char[]> { ToCharArray() }).)
I'm writing a small library that does some things that could have an exception thrown when an input argument is out of range. Seems straightforward that I would throw a std::out_of_range.
I would also like to generate a nice message, such as "You gave me X but Y is the maximum value in range" - i.e. I'm formatting a string and wish to use that for the exception.
What is odd is that the signature of the constructor is
explicit out_of_range (const string& what_arg)
That is, it takes a const reference to the string. Any string that I create on the stack will be destroyed as we pop out of the function, leaving a mangled heap of garbage for the catcher of the exception. so I have only a few options:
Use a string literal, so no nice generated message. It's valid for the lifetime of the program.
Make the string static in the function and rewrite it when thrown. Thread safety is not an issue for my program, but this feels way dirty.
Subclass out_of_range so that it takes a copy of string, and call the superclass constructor with a reference to the copy, such that the copy exists for the lifetime of the exception object.
I'm leaning toward 3 as the least gross, and arguably a better design than directly using the standard class anyway, but I have to ask: is there really no way to use the standard out_of_range class directly with a generated string? Am I missing something?
The exception will hold a copy of the string you passed in, not just a reference. You can safely create the string locally and pass it to the constructor of the exception without worrying about lifetime issues.
Note that the fact that the string is passed by reference does not inhibit the possibility of copying inside the constructor, which seems to have confused you.
Your assumptions are wrong. Imagine this class:
struct Foo
{
std::string s;
Foo(std::string const & str) : s(str) { }
};
Can you look a the constructor and conclude that Foo a(std::string("hello")); creates a dangling reference?
Your what_arg argument will be copied into a member of the exception in the ctor.
#include <iostream>
using namespace std;
int main (int argc, char* const argv[]) {
int a = 20;
cout<<"address of a is "<<&a<<endl;
try{
throw a;
}
catch (int& z) {
cout<<"address of z is "<<&z<<endl;
}
return 0;
}
The address of a is not same as that of z. It means reference doesn't work in try catch. If not then why compiler is not generating any error? And what does above code mean?
When you throw an object of any type, the Standard allows compilers to make copy of the object as many times as it wishes. Therefore, in the catch block, you might not get the original object you threw, and instead it can be a different object, which is a copy of the original object, or a copy of the copy of the copy of the original object, or so on.
I guess my comment was not so clear so I write something as answer.
When you throw that exception you throw it by value. It means that it'll be copied (it doesn't matter if it's a primitive type or a copied object). Of course when an object is copied then its memory location changes (it's a new object). Why this? Because exceptions can unroll the stack to find a proper catch block. If you throw something by reference what you may get is garbage (because when a variable goes out of scope it'll be destroyed). I said may because in reality the compiler does not allow to throw a reference and you'll always have a copy.
If your exception object is really big you may consider to allocate the object with new and then throw its pointer. But someone has to deallocate it. Are you ready for the risk? Take a look (as example) at the CException implementation on MFC and its Delete() method (they try to make this easy but I'm not really happy of that).
Maybe you wonder why if you have to throw by value you catch by reference. First because it's how std::exception is designed to be used (try to call the what() method of an exception catched by value). Second because it lets the compiler to perform some optimizations (moreover, even if you do not use std::exception, you won't create useless copies of that object).
Say I've written some function myFunc that can throw const char* exceptions:
void myFunc()
{
int returnCode = whatever();
if (!returnCode)
{
std::string msg;
msg.append("whatever function failed");
std::cerr << msg << std::endl; // print warning message
throw msg.c_str(); // throw warning message as exception
}
}
And later I'm using it like so:
void myProgram()
{
try
{
myFunc();
}
catch(const char* str)
{
// is 'str' string memory valid here?
}
}
I realize this isn't really a good strategy for exception usage: better to throw and catch exception classes, not strings. But I'm curious about the scoping involved here.
msg.str() returns a temporary std::string. As temporaries are deleted at the end of a statement ;, the contents of the character string returned by c_str() become undefined when the throw ... ; statement terminates by leaving the scope via the exception mechanism.
(The lifetime of the const char* temporary is obviously extended to reach to the catch handler, but that does not help since the underlying buffer is gone).
Throwing std::string (i.e. throw msg.str();) would work, the lifetime of the temporary would be extended as intended.
Indeed the c_str() call is acting on a temporary (string) object and the pointer will be invalid when you catch it.
Not only that, but since the stringstream and stringcould do allocation, you need to make sure that you're not throwing because of heap problems. If you're at that point due to being out of memory you may bomb out even worse trying to create your exception. You generally want to avoid heap allocation during exceptional cases.
Are you unable to use say runtime_error or create your own exception type?
Note that if you had said:
throw "error";
you would be OK because the lifetime of the string literal is the lifetime of the program. But don't do it, anyway!
Something Alexander Gessler did not mention in his answer, is the possibility of an exception being thrown by by std::string itself during the creation of the temporary string object.
std::exception is guaranteed not to throw an exception during construction, std::string has no such guarantee.
An alternative approach (for classes) is to declare a private std::string object in your class. Assemble the error message prior to the throw, and then throw the c_str(). This will throw a const char* exception, the error message being valid until the next exception is thrown from that class (which would presumably modify the error string again.)
A simple example can be found here: http://ideone.com/d9HhX
Although this was answered over ten years ago, I would give some supplement:
https://learn.microsoft.com/en-us/cpp/cpp/exceptions-and-stack-unwinding-in-cpp
In the C++ exception mechanism, control moves from the throw statement to the first catch statement that can handle the thrown type. When the catch statement is reached, all of the automatic variables that are in scope between the throw and catch statements are destroyed in a process that is known as stack unwinding.
That's to say, any variables in the stack, including object variable, or basic type(int, char, etc) will be destroyed.
When throw an object in c++, c++ will actually make a cloned object by invoking the object copy constructor, the cloned object lifetime will valid through throw-catch.
reference:
C++: Throwing an exception invokes the copy constructor?
Now, return to the OP question, so, "throw msg.c_str();" is invalid because the msg object
is deleted (it's a auto variable), it happens to work because the memory is still there but actually freed.
So, just as #AlexanderGessler, #MarkB suggested,
the best c++ practice is: always throw string object, runtime_error, instead of throwing string.c_str()
I'm currently working on a C++ project, where dynamic arrays often appear.
I was wondering, what could be the correct way to initialize a dynamic array using the new-operator? A colleague of mine told me that it's a no-no to use new within the constructor, since a constructor is a construct that shouldn't be prone to errors or shouldn't fail at all, respectively. Now let's consider the following example: We have two classes, a more or less complex class State and a class StateContainer, which should be self-explained.
class State {
private:
unsigned smth;
public:
State();
State( unsigned s );
};
class StateContainer {
private:
unsigned long nStates;
State *states;
public:
StateContainer();
StateContainer( unsigned long n );
virtual ~StateContainer();
};
StateContainer::StateContainer() {
nStates = SOME_DEFINE_N_STATES;
states = new State[nStates];
if ( !states ) {
// Error handling
}
}
StateContainer::StateContainer( unsigned long n ) {
nStates = n;
try {
states = new State[nStates]
} catch ( std::bad_alloc &e ) {
// Error handling
}
}
StateContainer::~StateContainer() {
if ( states ) {
delete[] states;
states = 0;
}
}
Now actually, I have two questions:
1.) Is it ok, to call new within a constructor, or is it better to create an extra init()-Method for the State-Array and why?
2.) Whats the best way to check if new succeeded:
if (!ptr) std::cerr << "new failed."
or
try { /*new*/ } catch (std::bad_alloc) { /*handling*/ }
3.) Ok its three questions ;o) Under the hood, new does some sort of
ptr = (Struct *)malloc(N*sizeof(Struct));
And then call the constructor, right?
You should let the std::bad_alloc propagate - there's likely nothing reasonable you could do anyway.
First of all, throwing an exception from the constructor is the only reliable way to signal a problem - if there's no exception it means the object is completely constructed. So catching std::bad_alloc alone will not help against other possible exceptions.
Then what can you do to "handle" it in such a way that the other code is aware and can react appropriately?
Use exceptions right - let them propagate to the site where they can be reasonably handled.
The entire purpose of a constructor is to construct an object. That includes initialization. When the constructor finishes executing, the object should be ready to use. That means the constructor should perform any initialization that is necessary.
What your friend suggests leads to unmaintainable and error-prone code, and goes against every good C++ practice. He is wrong.
As for your dynamic arrays, use std::vector instead. And to initialize it, simply pass a parameter to the constructor:
std::vector<int>(10, 20)
will create a vector of 10 integers, all of them initialized to the value 20.
Not a complete answer, just my 2 cents:
1: I would use new in the constructor, although for dynamic arrays, STL is the way to go.
2: the normal error-handling for new is to raise an exception, so checking the returned pointer is useless.
3: don't forget the new-operator to make the story a little bit more interesting.
Short answer:
No, your friend is wrong. The constructor is where you do allocation + initialization. We even have a term called "Resource Acquisition is Initialization" (RAII)... classes acquire resources as part of their initialization in the constructor and classes free those acquired resources in their destructors.
Long answer:
Consider the following code in a constructor:
member1 = new whatever1[n];
member2 = new whatever2[m];
Now, suppose in the above that the second allocation were to throw an exception, either because the construction of whatever2 failed and threw an exception, or the allocation failed and threw std::bad_alloc. The result is that the memory that you've allocated for whatever1 will have been leaked.
For this reason, it is better to use a container class such as std::vector:
MyClass::MyClass(std::size_t n, std::size_t m) : member1(n), member2(m) {}
// where member1 and member2 are of type std::vector
When using type std::vector, if the second allocation fails, the destructor of the previous std::vector will be invoked, causing the resources to be appropriately released. This is probably what your friend meant when he said you shouldn't be using new (you should be using a container class, instead), in which case he would be mostly correct... although there are smart pointer classes such as boost::shared_ptr which provide you with these same safety guarantees and where you would still need to use new, so he still isn't quite right.
Note that if you have only one object/array that you are allocating, then this is not an issue... which is the way things are in your code... you don't have to worry about leaks due to some other allocation failing. Also, I should add that new will either succeed or throw an exception; it will not return NULL, and so that check is pointless. The only instance where you should catch std::bad_alloc is in the case where you have been forced to do several allocations (you are forbidden from using std::vector), in which case you deallocate the other resources in the handler, but then you rethrow the exception, because you should let it propagate.
Your friend is somewhat right. However, it is common practice to do memory reservations in the Constructor, and deallocations in the Destructor.
The problem with methods that may fail in Constructors is as follows: The constructor has no traditional means of notifying the caller of the problem. The caller expects to get an object instance that is not corrupt in any way.
The solution to this problem is to throw/propagate an exception. The exception will always get through and can be handled by the caller.
If you are looking out for a return type i.e. if the function has to return a status then use the separate function (init()) to allocate memory.
If you check are going to check whether the memory got allocated by checking the NULL condition in all the member functions then allocate memory in the constructor itself.
The exception handling (i.e. try...catch) is a better choice.
Apart from calling the constructor the "this" pointer is also initialized.