What is the lifetime of an object immediately passed as a parameter? - c++

I had some code that looked something like the following:
struct fooclass {
char data[32];
}
fooclass makefoo() {
fooclass res;
// for example:
memset(res.data, 0, sizeof(res.data));
res.data[0] = 43;
return res;
}
struct do_stuff {
const fooclass& obj;
do_stuff(const fooclass& obj_in) : obj(obj_in) { }
void operate() { /* do things with obj; */ }
}
bool put_it_to_work(struct do_stuff& f) {
f.operate();
f.operate();
return true;
}
bool call_it_all() {
do_stuff local(makefoo());
return put_it_to_work(local);
}
With gcc, the code worked fine. With MSVC2012, local.obj became corrupted.
The question is: how long does the fooclass returned by makefoo last? Should it be until the end of call_it_all, or is it just until the end of the do_stuff local(makefoo()) line and I just got lucky? I'd appreciate a reference to the standard.

Here's your problem:
struct do_stuff {
const fooclass& obj;
obj is a reference, not a proper object, so no copy is ever made of the result of makefoo(). The real object that obj references is destructed when the local object has finished being constructed, specifically when the anonymous temporary variable that makefoo() returns is destroyed.
I think you were just lucky that it worked under gcc. Perhaps the object that obj refered to was being destroyed as it should be, only its data was left in RAM and the program appeared to work properly. Perhaps MSVC was "erased" the RAM that obj referred to such that attempts to use it would fail quickly.

Related

Passing pointer arguments to a double pointer argument

I have a sequence of calls where the final call requires a double pointer. It seems that I am always getting a null pointer in the end. I have simplified this down a lot to the following. The final call is a library call that returns a pointer.
This is the simplified mess. The foo in MainCaller is always 0 even though I know (through the libraries testing methods) that the object does exist.
void MainCaller(){
foo_t *foo;
MiddleProcessor(foo);
// foo results as 0
}
void MiddleProcessor(foo_t *foo){
if(1){
ProcessorA(foo);
}else{
ProcessorB(foo);
}
}
void ProcessorA(foo_t *foo){
FinalCall(&foo);
}
void FinalCall(foo_t **foo){
*foo = some_lib_call();
lib_call_test_is_good_foo(foo); // true :)
}
The problems are that you are passing the pointer by value and FinalCall never knows where the original lives.
These changes may help:
void MainCaller(){
foo_t *foo;
MiddleProcessor(&foo); // Passing the address of foo means foo can be overwritten
// foo results as 0
}
void MiddleProcessor(foo_t **foo){
if(1){
ProcessorA(foo);
}else{
ProcessorB(foo);
}
}
void ProcessorA(foo_t **foo){
FinalCall(foo);
}
void FinalCall(foo_t **foo){
*foo = some_lib_call();
lib_call_test_is_good_foo(foo); // true :)
}
Changing foo in FinalCall has no effect on foo in MainCaller. They're different variables why should changing one change the other?
Instead you want something like this
void MainCaller(){
foo_t *foo;
foo = MiddleProcessor();
}
foo_t* MiddleProcessor(){
if(1){
return ProcessorA();
}else{
return ProcessorB();
}
}
foo_t* ProcessorA(){
foo_t* foo;
FinalCall(&foo);
return foo;
}
void FinalCall(foo_t **foo){
*foo = some_lib_call();
lib_call_test_is_good_foo(foo); // true :)
}
In order to modify a parameter you need to pass by reference, which you can do with an explicit reference or a pointer. If the thing you want to change is a pointer, you need a reference to a pointer or a pointer to a pointer.

Object value can not be changed

I am a new c++ programmer, and have learned some java before. I am do my assignment. And I just could not get my heard around this problem.
class A{
private:
bool test;
public:
void anotherSetTest();
void setTest();
A();
};
void Globle_scope_function(A a){
a.setTest(true);
}
A::A(){
test = false;
}
void A::setTest(bool foo){
test = foo;
}
void A::anotherSetTest(){
Globle_scope_function(*this);
}
int main(){
A a;
a.anotherSetTest();
cout<<a.getTest()<<endl;//It suppose to output true, but why does it output false.
system("pause");
return 0;
}
When I use visual studio to debug, it tells me that the object has gone out of scope. How do I solve it... :-< . Edit it to MWV.
Calling Globle_scoop_function(*this); takes a deep copy of *this to the function parameter a. It's that object that goes out of scope at the end of Globle_scoop_function. The object *this remains unmodified.
One remedy would be to change the prototype to void Globle_scoop_function(A& a){. Note the & which denotes a reference. You then modify the a in main() through that reference.
The fact that all the various instances of A in your code are all called a only adds to the confusion.

Problems with nested object in functional object of the tbb::flow::graph

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

Behaviour in Release Build I cant understand

While trying to find out a problem that occurs only in a release build and not in the debug build I noticed the following behaviour (String would be invalid and would not point to anything while the int would be fine). I have given code below which gives an idea of what I was going through
typedef boost::shared_ptr<MyClass> shared_cls
typedef std::deque<shared_cls> vector_def;
typedef boost::shared_ptr<vector_def> shared_vector_def;
typedef boost::unordered_map<int,shared_vector_def> inner_map_def;
typedef boost::shared_ptr<inner_map_def> shared_inner_map_def;
static boost::unordered_map<std::string,shared_inner_map_def> bcontainer;
shared_cls& SomeMethod(const std::string& symb,const int& no)
{
shared_inner_map_def tshare = bcontainer[symb];
shared_vector_def tmp = tshare->at(no);
shared_cls t = tmp->back();
return t
}
The object MyClass looks like this
class SomeClass
{
private:
int i;
std::string s;
void set_i(int rx)
{
i = rx;
}
int get_i()
{
return i;
}
void set_s(std::string rx)
{
s = rx;
}
std::string get_s()
{
return s;
}
}
Now when I use the above method as in the following code
void main()
{
shared_cls r = SomeMethod("IBM",12);
//Here r does not have a valid string s
//However it does have a valid int i
}
Now my question is in the above main when I call the SomeMethod the r returned does not have a valid string s. It has a scrambled value I found this out by using a logger. However the value of s is totally find during the function SomeMethod. I resolved this issue by not returning the shared pointer by reference.In that case it works. Why does removing the reference make it work
Your shared_cls t goes out of scope because it is defined in the function SomeMethod itself. You need to return shared pointers by value if they are defined in the scope. In the link, it is explained why it is dangerous to return the reference of a temporary object.
In the case of std::string, string has a reference counting mechanism and when it's reference is decremented to zero, it becomes invalidated and a segmentation fault may be observed in such a case. Even if member int i is returned properly, it is still undefined behavior.

Object dependency and handling situations when one of them doesn't exist anymore

There is this code:
#include <iostream>
class CleverClass{
public:
CleverClass() : number(55){}
void cleverOperation(){
std::cout << number << std::endl;
}
private:
int number;
};
class NotCleverClass{
public:
NotCleverClass(CleverClass* cc) : cleverClass(cc){}
void callCleverOperation(){
// throw exception when cleverClass object doesn't exist anymore
cleverClass->cleverOperation();
}
private:
CleverClass* cleverClass;
};
NotCleverClass returnNCC(){
CleverClass CC;
NotCleverClass NCC(&CC);
NCC.callCleverOperation(); // prints 55
return NCC;
}
int main()
{
NotCleverClass returnedNCC = returnNCC();
returnedNCC.callCleverOperation(); // prints -858993460
return 0;
}
Object of class NotCleverClass is dependent to object of class CleverClass. When object of class CleverClass exists then object of class NotCleverClass can use its function cleverOperation() and everything works okey. However, when object of class CleverClass is going to lose existence, then calling its function may cause troubles.
One of the solutions is to keep in NotCleverClass weak pointer (boost::weak_ptr) of CleverClass object with reference checker, but there is still a problem when object of cleverClass is not going to be placed on free store (for example on stack). Are there some design patterns to monitor whether used object still exist and that calling its functions has any sense?
You can still use a weak_ptr even if the object has automatic storage duration; you can give the shared_ptr a custom deleter that does nothing; and make sure it is destroyed immediately before the object itself, by placing it in the same scope as the object. Something like this:
class NotCleverClass{
public:
NotCleverClass(weak_ptr<CleverClass> cc) : cleverClass(cc){}
void callCleverOperation(){
// throw bad_weak_ptr when cleverClass object doesn't exist anymore
shared_ptr<CleverClass>(cleverClass)->cleverOperation();
}
private:
weak_ptr<CleverClass> cleverClass;
};
struct null_delete { void operator()(void*) const {} };
NotCleverClass returnNCC(){
CleverClass CC;
shared_ptr<CleverClass> shared_cc(&CC, null_delete());
NotCleverClass NCC(shared_cc);
NCC.callCleverOperation(); // prints 55
return NCC;
// shared_cc destroyed here: NCC::cleverClass is safely invalidated
// CC destroyed here: no dangling references remain
}
This should work with either Boost or C++11 smart pointers. In C++11, you can replace the null_delete functor with a lambda, [](void*){}.
One solution would be for CC to have static storage duration:
NotCleverClass returnNCC(){
static CleverClass CC; // Note the keyword static there
NotCleverClass NCC(&CC);
NCC.callCleverOperation(); // prints 55
return NCC;
}
This way CC is constructed only once when returnNCC() is called for the first time and stays alive as long the program is running.