Let's say someString initialization is a tad complicated, hence we write a simple member function stringInitialization() with which to initialize someString in the body of the constructor:
class DemoL {
private:
int someNumber;
std::string someString;
void stringInitialization() {
if (someNumber == 1) {
someString = "FIRSTSTRING";
} else if (someNumber == 2) {
someString = "SECONDSTRING";
} else {
someString = "";
}
}
public:
explicit DemoL(int rNumber) :
someNumber(rNumber) {
stringInitialization();
}
};
This way, I'd assume, someString will be default initialized before the body of the constructor and only after that will it be modified by calling stringInitialization().
So, let's modify the code a bit, so that we initialize someString in the constructor initializer list:
class DemoL {
private:
int someNumber;
std::string someString;
std::string stringInitialization() const {
if (someNumber == 1) {
return "FIRSTSTRING";
} else if (someNumber == 2) {
return "SECONDSTRING";
} else {
return "";
}
}
public:
explicit DemoL(int rNumber) :
someNumber(rNumber),
someString(stringInitialization()) {}
};
Would you be so kind as to tell me whether the second variant is more efficient and correct?
Your assumption is correct. The constructor DemoL(int rNumber) needs to be able to default construct the member someString and this is no problem because std::string is default constructible.
One obvious point is that one member could be not default-constructible, in which case you would have to initialize it.
But even if it is, default constructing it could be a waste of resources, if you are changing it right after, so the second alternative seems better to me as it goes straight to the point.
However, since stringInitialization returns by value, I would use std::move, no, this is actually a bad idea, as pointed out in the comments.
So as a conclusion:
the two codes are the same as regards someNumber
the first code default-initializes someString ("calls" std::basic_string<...>::basic_string) and then assigns it (calls std::basic_string<...>::operator=)
the second code constructs the return std::string value from the sting literals when the call to stringInitialization returns (calls basic_string<...>::basic_string(const char*)), and then copy-constructs someString (calls basic_string<...>::basic_string(basic_string&&)); actually copy elision happens because stringInitialization returns an rvalue.
Related
Couldn't find the answer in any similar-named question.
I want a user to be able to initialize a string member at any point in the lifetime of an object, not necessarily on construction, but I want them to know that the object is invalid until the string is initialized...
When creating a simple class, say the following:
#include <string>
class my_class {
public:
my_class() : _my_str() { }
my_class(const std::string & str) : my_class() {
set_my_str(str);
}
std::string get_my_str() const {
return _my_str;
}
void set_my_str(const std::string & str) {
_my_str = str;
}
private:
std::string _my_str;
};
and a user creates an empty instance of the class (i.e. using the empty constructor), _my_str will be an empty/uninitialized string?
So, I see two ways of handling behavior: the way mentioned above, where an empty string is returned, or a possible second way:
#include <string>
class my_class {
public:
my_class() : _my_str(), _my_str_ptr(nullptr) { }
my_class(const std::string & str) : my_class() {
set_my_str(str);
}
std::string * get_my_str() const {
return _my_str_ptr;
}
void set_my_str(const std::string & str) {
_my_str = str;
_my_str_ptr = &_my_str;
}
private:
std::string _my_str;
std::string * _my_str_ptr;
};
Where you return a nullptr, and you maintain a pointer to a local variable?
Is that valid behavior? Which way is preferred and why? Wouldn't the second way be better since you are telling the user, "listen, this object is currently invalid, you need to initialize it" while still implying that you are managing the lifetime of such object.
_my_str will be an empty/uninitialized string?
Empty, yes. Uninitialized, no. It's completely initialized (to an empty string).
Where you return a nullptr, and you maintain a pointer to a local variable?
Is that valid behavior?
Yes it's valid, but
Which way is preferred and why? Wouldn't the second way be better since you are telling the user, "listen, this object is currently invalid, you need to initialize it" while still implying that you are managing the lifetime of such object.
It makes absolutely no sense to maintain two distinct member variables for this. It sounds like what you need is std::optional (or the equivalent in Boost, boost::optional), so that _my_str has two states: empty/invalid (contains no string) and non-empty/valid (contains a string):
#include <string>
#include <experimental/optional>
using std::experimental::optional;
class my_class {
public:
my_class() /* default-initializes _my_str as empty */ { }
my_class(const std::string & str) : _my_str(str) { }
const std::string * get_my_str() const {
if (_my_str) // if it exists
return &*_my_str; // return the string inside the optional
else
return nullptr; // if the optional is empty, return null
}
/* Or simply this, if you don't mind exposing a bit of the
implementation details of the class:
const optional<std::string> & get_my_str() const {
return _my_str;
}
*/
void set_my_str(const std::string & str) {
_my_str = str;
}
private:
optional<std::string> _my_str;
};
If "" (an empty string) can be used as a sentinel value to signify the "empty/invalid" state in your case, then you can just do this:
#include <string>
class my_class {
public:
my_class() /* default-initializes _my_str as "" */ { }
my_class(const std::string & str) : _my_str(str) { }
const std::string * get_my_str() const {
if (!_my_str.empty()) // if it'a non-empty
return &_my_str; // return the non-empty string
else
return nullptr; // if it's empty, return null
}
void set_my_str(const std::string & str) {
_my_str = str;
}
private:
std::string _my_str;
};
In general, the pattern you're referring to is called Null object pattern.
The "oldest way" of implementing it was using one of possible values of a variable and reserving it for "no value" meaning. In case of a string an empty string commonly was used in such a way. Obviously not always possible, when all values were needed.
The "old way", was always using a pointer - (const T* get_t() const). This way the whole range of variable values could be meaningful, and still "no value" semantics were available by means of returning a null pointer. This was better, but still pointers are not as comfortable to use, not safe. Nowadays, pointers are usually bad engineering.
The modern way is optional<T> (or boost::optional<T>).
An empty std::string value is not per definition invalid. It is just empty.
On important difference is that the second "get_..." approach does not copy the object but gives the user a non const pointer to the internal string which leads to violation of const correctness since you imply that the class may not be changed by having const at the get method while still providing a pointer that may change the internal state.
If your logic implies that "empty string" == "invalid" and if this is a possible state there is not much of a difference whether the user must do
if (get_my_str())) // use valid pointer to nonempty string versus
if(!get_my_str().empty()) // use valid nonempty string
I think.
You'd want to return std::string const & from your get method and leave it to the user wether to copy the object or not.
4.1. No forced copy (versus by value return std::string)
4.2. No pointer which may be nullptr and accidentally dereferenced.
4.3. Passing around and storing a pointer which may outlive the object is more common that dangling references.
I want a user to be able to initialize the string later on, not necessarily on construction, but I want them to be able to know that the object is invalid until the string is initialized...
The question is: Is an empty string actually a "valid" value after proper initialization?
If yes: use optional to add one additional state signaling validity.
If no: let the emptyness of the string stand for invalidity of your object.
I have a functional object that I'm using as body for multifunction_node:
class module
{
private:
bool valid;
QString description;
bool hasDetectionBranch;
tDataDescription bufData;
void* dllObject; //<-- This is a pointer to an object constructed with help of the external dll
qint64 TimeOut;
public:
module(const QString& _ExtLibName);
virtual ~module();
void operator() (pTransmitData _transmitData, multi_node::output_ports_type &op);
};
'dllObject' is created at construction time of the object 'module':
module::module(const QString& _ExtLibName) :
valid(true), hasDetectionBranch(false)
{
GetObjectDescription = (tGetObjectDescription)QLibrary::resolve(_ExtLibName, "GetObjectDescription");
CreateObject = (tCreateObject)QLibrary::resolve(_ExtLibName, "CreateObject");
DestroyObject = (tDestroyObject)QLibrary::resolve(_ExtLibName, "DestroyObject");
if (!CreateObject || !DestroyObject || !GetObjectDescription)
valid = false;
else
{
description = QString(GetObjectDescription());
dllObject = CreateObject();
}
}
And this is when 'dllObject' is destroyed:
module::~module()
{
if (valid)
{
DestroyObject(dllObject);
}
}
I've built a little graph:
void MainWindow::goBabyClicked(void)
{
module mod(QString("my.dll")); //<-- Here is OK and mod.dllObject is correct
if (!mod.isValid())
{
qDebug() << "mod is invalid!\n";
return;
}
first fir(input);
folder fol(QString("C:/out"), 10000);
graph g;
source_node<pTransmitData> src(g, fir, false);
multi_node mnode(g, tbb::flow::serial, mod); //<-- WTF? ~module() is executed!
function_node<pTransmitData> f(g, tbb::flow::serial, fol);
make_edge(src, mnode);
make_edge(mnode, f);
src.activate();
g.wait_for_all();
}
So I have 2 questions:
1) Why ~module() is executed and how to prevent this?
2) How to keep pointer for nested object correctly?
UPDATE Added some dummy code to prevent destroying dllObject at first time like:
bool b = false;
module::~module()
{
if (valid && b)
{
DestroyObject(dllObject);
}
if (!b)
b = true;
valid = false;
}
Now it works as expected but looks ugly :/
Max,
I assume you have a typedef of multi_node which is similar to the one in the reference manual example.
The constructor for the multifunction_node has the following signature:
multifunction_node( graph &g, size_t concurrency, Body body );
The body object is copied during the parameter passing and also during the construction of the node, so there are two copies of mod created during construction (actually three, as an initial copy of the body is also stored for re-initializing the body when calling reset() with rf_reset_bodies). The destructor calls you are seeing are probably those used to destroy the copies.
The body object should also have a copy-constructor defined or be able to accept the default-copy-constructor to make copies of the body. I think the QString has a copy-constructor defined, but I don't know about fields like tDataDescription. (I thought we had covered the basic requirements for Body objects in the Reference Manual, but I am still looking for the section.) In any case, the Body class must be CopyConstructible, as it is copied multiple times.
Regards,
Chris
I have a class that holds a large table of data, with a constructor that takes all of the parameters needed to calculate that data. However, it takes a long time to run, so I've added a constructor that takes a stream, and reads the data in from that stream. I'm having trouble coming up with a RAII way of designing this class though, since I have two constructors, and at run time I need to choose between them. This is what I've come up with:
std::string filename; // Populated by command line arguments
DataTable table; // Empty constructor, no resource acquisition or initialization
if( filename.empty() ) {
table = DataTable(/*various parameters*/);
} else {
std::ifstream filestream(filename);
table = DataTable(filestream); // Reads from file
}
That looks pretty fragile to me. The default constructor will leave the object in a valid state, but a useless one. The only use of it is to create a "temporary" object in the outer scope, to be assigned to in one of the branches of the if statement. Additionally, there's a flag "inited" behind the scenes to manage if the object was default-constructed or fully initialized. Is there a better way to design this class?
Maybe like this:
DataTable foo = filename.empty()
? DataTable(x, y, z)
: DataTable(std::ifstream(filename));
Move the file test code that decides which way to init into the ctor, move the ctors into two private init functions, call one of these from the ctor or throw an exception if everything fails.
Some thoughts:
Get rid of the "inited" flag.
Get rid of the default constructor if it can't sensibly construct the object
use this kind of construct to get you a DataTable:
DataTable get_me_my_data_fool(ParameterTypes... params, const string& filename = "")
{
if(!filename.empty())
return DataTable(std::ifstream(filename)); // check if file exists!
else
return DataTable(params...);
}
Actually, now that I think about it, it would be better to just put this logic into the DataTable constructor.
If the class supports copy, then Kerrek SB's solution is the way
to go. From what you say, however, copying is expensive. In
that case, and you can use C++11, you might try adding a move
constructor, in order to avoid the deep copy. Otherwise, you're
probably stuck allocating dynamically:
std::auto_ptr<DataTable> fooPtr( filename.empty()
? new DataTable( x, y z )
: new DataTable( filename ) );
DataTable& foo = *fooPtr;
Here's another idea for completeness sake:
template<typename T>
class uninitialised
{
public:
~uninitialised()
{
if (alive_) {
operator T&().~T();
}
}
template<typename... Ts>
void create(Ts&&... args)
{
assert(!alive_ && "create must only be called once");
void* const p = obj_;
::new(p) T(std::forward<Ts>(args)...);
alive_ = true;
}
operator T&()
{
assert(alive_ && "T has not been created yet");
return *reinterpret_cast<T*>(obj_);
}
private:
bool alive_ = false;
alignas(T) unsigned char obj_[sizeof(T)];
};
// ...
std::string filename;
uninitialised<DataTable> table;
if (filename.empty()) {
table.create(/* various parameters */);
} else {
std::ifstream filestream(filename);
table.create(filestream);
}
DataTable& tbl = table;
Is it possible to initialize a variable from a return parameter (by ref)? Say I have something like:
Car c; // <- don't want to create a new Car here!
if (findCar("beetle", c)) {
...
}
where if findCar succeeds, it returns true and fills c:
bool findCar(string name, Car& out) {
...
// return true if found
out = thecar;
return true;
}
Now, my class Car doesn't have a 0-argument constructor, so the above code fails to compile. Is there a way to keep c uninitialized until the call to findCar?
Solutions I thought of are:
adding a cheap 0-argument constructor to Car
switch to pointers (which I'd rather avoid)
Sort of. The problem is that a reference absolutely must refer to an actual object. So, if you return by reference then someone must create an object for that returned reference. Therefore if you can't find a matching object, it's not really meaningful to return a reference. If you pass a reference in, then you must create an object first, for the argument to refer to.
You could work around this for example as follows:
Car &findCar(const string &name) {
...
// return if found, else throw
if (found it) {
return thecar; // assuming `thecar` means some already-existing object,
// if it's a local variable then return by value!
} else {
throw std::runtime_error(name);
}
}
Caller does:
Car c = findCar("beetle");
or Car &c = findCar("beetle"); if they want to "see" the actual object found rather than a copy of it. If findCar wants callers to only ever see a copy, not some internal object, then of course you can return by value rather than by reference - the difference is one & in the function signature.
And someone somewhere has to handle the exception.
If you'd prefer to avoid exceptions then the right thing to return from a find function is a pointer (or other iterator). It's what the standard containers and algorithms do when searching, and there are special values (end iterators, or you could use null pointers) that mean "not found".
Whenever an object variable (which is not a pointer or reference) exists, it contains the whole data of the object, which means that it has to be always initialized, so yes, you will have to use one of your suggested solutions.
By the way, if you don't use a pointer or reference, you also can't store objects of derived classes in the variable, so i would suggest switching to pointers.
Object are initialized as soon as you declare them as variable.
If you want late initialization you have to use pointer and:
Car *c;
bool findCar(string name, Car * &out){
...
out = new Car();
}
don't forget to delete it
No, this isn't possible. If the parameter signature takes a car reference, it must point to a car object. You have two solutions for only having the object created at the right, as late as possible time, use pointers like this:
car* find_car(string name) {
...
return nullptr;
}
car* c = find_car(...);
if (c != nullptr) {
...
}
or to use exceptions, which probably isn't what you want
car find_car(string name) {
...
throw new runtime_error("car not found");
}
Basically declaring it as a reference means you're guaranteeing the object has been constructed, so that requirement needs to give. I'd use pointers personally.
You can return Car from your function:
struct Car
{
Car():_isValid(false){}
Car(const Car&);
bool isValid();
};
Car findCar (const string& name);
Car car = findCar("beetle");
if (car.isValid()){
...
}
other variant is to throw excpetion, if findCar cannot find any car:
struct Car
{
Car(const Car&);
};
Car findCar (const string& name) {
....
if (noCarFound) throw CarNotFoundException();
....
}
try{
Car car = findCar("beetle") {
}
catch (CarNotFoundException e) {
....
}
Or create Car constructor that accepts string
I am not very experienced at C++ but also I know this is not the cleanest solution.
However here is an approach:
bool findCar(string name, Car **out) {
// first make out to null
*out = NULL;
...
// if found
if(found){
*out = &thecar;
return true;
}
// otherwise return false. Notice that out remains pointing null
return false;
}
Now, anywhere in the code you should have:
Car *c; // <- You don't create a new Car here!
if (findCar("beetle", &c)) {
...
}
Hope you find it helpful
I have a question about the following code:
let's say I have a class P that has a copy constructor and a regular constructor the receives one string value.
I have the following code:
P doSomething(){
P p("myValue");
return p;
}
int main(){
P m=doSomething();
return 1;
}
why isn't copy constructor invoked at the return p of the doSomething() function?
the call P m=doSomething() - does it suppose to call the copy constructor or the operator=?
in case it's operator =, what is the difference of this code and the following:
P new_val=("newVal");
p m=new_val;
(i know here the call is for copy constructor)
Thanks,
Mary
why isn't copy constructor invoked at the return p of the doSomething() function?
The standard allows this copy to be elided. Google for [N]RVO. On certain compilers this happens only when optimizing, on others it is part of the calling conventions and thus happens always.
the call P m=doSomething() - does it suppose to call the copy constructor or the operator=?
T t = x; is "syntactic sugar" (in the sense that the T(x) is happening implicitly) for T t(T(x)) and thus has -- despite the = -- nothing to do with operator=. Note that also here the additional temporary may be elided, thus no copy ctor is called.
in case it's operator =, what is the difference of this code and the following:
This code makes no sense, what did you really mean?
P new=("newVal");
p m=new;
I made a small sample for demonstration.
void print(char* text, int ident)
{
for(int i = 0 ; i < ident ; i++)
{
printf(" ");
} // end for
fprintf(stdout, text);
fprintf(stdout, "\n");
fflush(stdout);
}
class P
{
public:
char* _str;
P (P& arg)
{
print("copy constructor", 2);
arg._str = this->_str;
}
P (char* str)
{
print("constructor", 2);
_str = str;
}
};
P doSomething(){
print("do something - function", 1);
P p("myValue");
print("before return p", 1);
return p;
}
int main(int argc, char* argv[])
{
print("start", 0);
P m=doSomething();
print("stop - call return", 0);
return 1;
}
this returns
start
do something - function
constructor
before return p
copy constructor
stop - call return
so copy constructor WILL BE CALLED
1) why isn't copy constructor invoked at the "return p" of the doSomething() function?
it should - try printing something to the console in the copy c-tor to see if it is really running.
2) the call P m=doSomething() - does it suppose to call the copy constructor or the operator=?
should call the operator=. again, use the debug message print from within the method to check
3) in case it's operator =, what is the difference of this code and the following:
P new=("newVal"); p m=new; (i know here the call is for copy constructor)
did you miss something on the code snippet? i think it won't compile