1

Originally, I have some code that looks like

class Ball
{
public:
    double x , y ;
    ofstream out ;
} ;

int main()
{
    Ball array[N] ;

    array[0].out.open("./position_1.txt") ;
    array[1].out.open("./position_2.txt") ;

    ......
}

where N is a run-time determined constant. But it suffers variable length arrays problem recently.

I try to follow the suggestion by this post Can't set variable length with variable by using STL container.

int main()
{
    vector<Ball> Balls ;
    Ball b ;

    b.out.open( "./position_1.txt" ) ;
    Balls.push_back( b ) ;
    ......
}

It fails at push_bak(), since stream can not be copied.

I can't determine the number of balls before running and I have to store the file stream instead of path for efficiency (preventing opening and closing files).

Is there any way to achieve the goal? Thanks

Community
  • 1
  • 1
maythe4thbewithu
  • 387
  • 1
  • 2
  • 12
  • What is the goal you are trying to achieve? Load a variable count of ball coordinates from a single file? – Spook Feb 06 '13 at 07:53
  • Yes, I have many images of balls and each image has many balls. – maythe4thbewithu Feb 07 '13 at 01:24
  • I have many images and each image has many balls. The ball numbers is fixed for each movie, but it is determined after first identification. I want to track them, 1, 2,.. and save them to 1.txt, 2.txt,..So I keep the file stream for each one for easy access and efficiency. Now, I maintain/new an array of streams outside the class and change "ofstream out" to be "ofstream *out"...Similar to the suggestions below. Thanks for your suggestion. But I wounder if there is a more "nature" way like the suggestion of using C++11. But, my gcc is not support C++11. I can't check so far. still thanks – maythe4thbewithu Feb 07 '13 at 02:08

3 Answers3

3

C++ streams are not copyable, but they're movable, so you can do this instead:

Balls.push_back( std::move(b) );

//DO NOT use b after push_back, as it has been moved!

and the default move-semantic generated by compiler for your class will work fine with this.

In C++11, you can write this:

std::vector<Ball> balls(N); //N is known at runtime

balls[i].out.open( "./position_1.txt" ); //i <= i < N

Note that this will not work in C++03, as in C++03 vector's constructor creates N copies of a default created object of type Ball. In C++11, however, it doesn't make any copy!

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    Or, since there is hardly ever a reason to use `open` or `close` on a `std::stream`, `balls.emplace_back("./position_1.txt")`, which would require a reasonable `Ball` constructor, though. – Christian Rau Feb 06 '13 at 09:17
1

If your compiler/library are old enough that they don't support move semantics for streams yet (many don't) you might consider storing a (smart) pointer to a stream in the structure instead. You do probably want it to be a smart pointer though -- handling ownership transfer correctly on your own is likely to be quite a bit of work to get right.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

Then make Balls a vector of pointers to Ball. Allocate the Ball objects with new and push_back the pointers.

Note that, if you use simple pointers, you must delete the Ball objects at the end with a loop. You can avoid this by using smart pointers, like std::tr1::shared_ptr.

comocomocomocomo
  • 4,772
  • 2
  • 17
  • 17