Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Message from discussion On callbacks
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
crai...@ee.washington.edu  
View profile  
 More options Sep 16 2009, 2:12 pm
From: <crai...@ee.washington.edu>
Date: Wed, 16 Sep 2009 11:12:06 -0700
Local: Wed, Sep 16 2009 2:12 pm
Subject: RE: On callbacks
Hi Christian,

Heh, heh.  You have run into the really hard part -- the inevitable error
messages.

You are closer than you may think, though.

If it were me, I would try something new on a scale much smaller than you
have attempted.  I would take the "simplest example" that I posted a few
days ago as a starting point and make a tiny change to try and turn it into
a bound callback to see what happened.  If you did that, you might end up
with:

---------- Begin Included File ----------

#include <iostream>
#include "ns3/object.h"
#include "ns3/uinteger.h"
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"

using namespace ns3;

class MyObject : public Object
{
public:
  static TypeId GetTypeId (void)
  {
    static TypeId tid = TypeId ("MyObject")
      .SetParent (Object::GetTypeId ())
      .AddConstructor<MyObject> ()
      .AddTraceSource ("MyInt",
                       "A Int value to trace.",
                       MakeTraceSourceAccessor (&MyObject::m_myInt))
      ;
    return tid;
  }

  MyObject () {}
  TracedValue<uint32_t> m_myInt;

};

void
IntTrace (uint32_t someBoundValue, uint32_t oldValue, uint32_t newValue)
{
  std::cout << "Traced " << oldValue << " to " << newValue << " with " <<
someBoundValue << std::endl;

}

int
main (int argc, char *argv[])
{
  Ptr<MyObject> myObject = CreateObject<MyObject> ();

  uint32_t someBoundValue = 1234;

  myObject->TraceConnectWithoutContext ("MyInt", MakeBoundCallback
(&IntTrace, someBoundValue));
  myObject->m_myInt = 2468;

}

---------- End Included File ----------

You will find that this example works fine (Notice your version got the
bound value in the wrong place).

A physics professor of mine once called the following technique adiabatic
programming.  Make a single tiny change to a working program.  The next tiny
change would be to try and use the stream as the bound parameter.

---------- Begin Included File ----------

#include <iostream>
#include <fstream>
#include "ns3/object.h"
#include "ns3/uinteger.h"
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"

using namespace ns3;

class MyObject : public Object
{
public:
  static TypeId GetTypeId (void)
  {
    static TypeId tid = TypeId ("MyObject")
      .SetParent (Object::GetTypeId ())
      .AddConstructor<MyObject> ()
      .AddTraceSource ("MyInt",
                       "A Int value to trace.",
                       MakeTraceSourceAccessor (&MyObject::m_myInt))
      ;
    return tid;
  }

  MyObject () {}
  TracedValue<uint32_t> m_myInt;

};

void
IntTrace (std::ofstream ascii, uint32_t oldValue, uint32_t newValue)
<========= change int to ofstream
{
  std::cout << "Traced " << oldValue << " to " << newValue << " with " <<
ascii << std::endl;

}

int
main (int argc, char *argv[])
{
  Ptr<MyObject> myObject = CreateObject<MyObject> ();

  std::ofstream ascii;  <===== change int to ofstream (and in the
MakeBoundCallback below)

  myObject->TraceConnectWithoutContext ("MyInt", MakeBoundCallback
(&IntTrace, ascii));
  myObject->m_myInt = 2468;

}

---------- End Included File ----------

But then when you try and build it -- boom, it blows up in your face.

---------- Begin Included Capture ----------

[ns-regression] ~/repos/ns-3-allinone-test/ns-3-dev > ./waf
Waf: Entering directory
`/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
[639/740] cxx: scratch/test-bound.cc -> build/debug/scratch/test-bound_2.o
/usr/include/c++/4.2/bits/ios_base.h: In copy constructor
â?~std::basic_ios<char, std::char_traits<char> >::basic_ios(const std:
:basic_ios<char, std::char_traits<char> >&)â?T:
/usr/include/c++/4.2/bits/ios_base.h:779: error:
â?~std::ios_base::ios_base(const std::ios_base&)â?T is private
/usr/include/c++/4.2/iosfwd:55: error: within this context
/usr/include/c++/4.2/iosfwd: In copy constructor
â?~std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(const
std
::basic_ofstream<char, std::char_traits<char> >&)â?T:
/usr/include/c++/4.2/iosfwd:92: note: synthesized method
â?~std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::
basic_ios<char, std::char_traits<char> >&)â?T first required here
/usr/include/c++/4.2/streambuf: In copy constructor
â?~std::basic_filebuf<char, std::char_traits<char> >::basic_filebuf(const st
d::basic_filebuf<char, std::char_traits<char> >&)â?T:
/usr/include/c++/4.2/streambuf:794: error: â?~std::basic_streambuf<_CharT,
_Traits>::basic_streambuf(const std::basic_streambuf<
_CharT, _Traits>&) [with _CharT = char, _Traits = std::char_traits<char>]â?T
is private
/usr/include/c++/4.2/iosfwd:86: error: within this context
/usr/include/c++/4.2/iosfwd: In copy constructor
â?~std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(const
std
::basic_ofstream<char, std::char_traits<char> >&)â?T:
/usr/include/c++/4.2/iosfwd:92: note: synthesized method
â?~std::basic_filebuf<char, std::char_traits<char> >::basic_filebuf(con
st std::basic_filebuf<char, std::char_traits<char> >&)â?T first required
here
../scratch/test-bound.cc: In function â?~int main(int, char**)â?T:
../scratch/test-bound.cc:45: note: synthesized method
â?~std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(cons
t std::basic_ofstream<char, std::char_traits<char> >&)â?T first required
here
../scratch/test-bound.cc:45: error:   initializing argument 2 of
â?~ns3::Callback<R, T1, T2, ns3::empty, ns3::empty, ns3::empty,
 ns3::empty, ns3::empty, ns3::empty, ns3::empty> ns3::MakeBoundCallback(R
(*)(TX, T1, T2), ARG) [with R = void, TX = std::ofstre
am, ARG = std::basic_ofstream<char, std::char_traits<char> >, T1 = uint32_t,
T2 = uint32_t]â?T
Waf: Leaving directory
`/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Build failed
 -> task failed (err #1):
        {task: cxx test-bound.cc -> test-bound_2.o}
[ns-regression] ~/repos/ns-3-allinone-test/ns-3-dev >

---------- End Included Capture ----------

But all you have done is changed the type of the bound variable!  

This must be due to that variable change.  It turns out that an ofstream
doesn't have a copy constructor.  Think about what it would mean to copy and
ofstream.  What are the semantics?  Since you can't predict that correctly,
ofstream doesn't allow copies.  

It turns out that an ofstream doesn't have value semantics!  

You have run into a problem using the stl, not ns-3 :-)

You have to pass around the *address* of the ofstream instead of passing it
by value.

---------- Begin Included File ----------

#include <iostream>
#include <fstream>
#include "ns3/object.h"
#include "ns3/uinteger.h"
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"

using namespace ns3;

class MyObject : public Object
{
public:
  static TypeId GetTypeId (void)
  {
    static TypeId tid = TypeId ("MyObject")
      .SetParent (Object::GetTypeId ())
      .AddConstructor<MyObject> ()
      .AddTraceSource ("MyInt",
                       "A Int value to trace.",
                       MakeTraceSourceAccessor (&MyObject::m_myInt))
      ;
    return tid;
  }

  MyObject () {}
  TracedValue<uint32_t> m_myInt;

};

void
IntTrace (std::ofstream *ascii, uint32_t oldValue, uint32_t newValue)
<===== pointer to ofstream!
{
  std::cout << "Traced " << oldValue << " to " << newValue << " with " <<
ascii << std::endl;

}

int
main (int argc, char *argv[])
{
  Ptr<MyObject> myObject = CreateObject<MyObject> ();

  std::ofstream ascii;

  myObject->TraceConnectWithoutContext ("MyInt", MakeBoundCallback
(&IntTrace, &ascii));
  myObject->m_myInt = 2468;

}

---------- End Included File ----------

This compiles just fine.

We usually frown on passing pointers around in ns-3, but prefer to use
Objects and our reference counting system.  The example above works, but you
have got to be very, very careful about the lifetime of that ofstream.

If you look at the CsmaHelper, you will see that the MakeBoundCallback takes
a Ptr<PcapWriter> as the bound parameter.  This points to an Object that, in
turn, holds the ofstream object; and so you can pass the Ptr<PcapWriter>
around by value just fine.  As long as someone has a reference to the
underlying writer it stays around taking care of the lifetime issue
automagically.

So I would take that approach and make my own kind of writer.

I think you are getting really, really close here.

Regards,

-- Craig


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.