Hi,
I was wondering if there is a single line initializing an array allocated by new?
Something like this:
PS: I know it is wrong.Code:int *p = new int[3] {1, 2, 3};
Thanks!
Hi,
I was wondering if there is a single line initializing an array allocated by new?
Something like this:
PS: I know it is wrong.Code:int *p = new int[3] {1, 2, 3};
Thanks!
That's almost exactly the Java syntax, but unfortunately, as far as I know, there's no way to do this in C++.
If you know the data, you probably don't need to dynamically allocate an array for it, though. Because you can certainly do this, as I'm sure you're aware.
Code:int p[] = {1, 2, 3};
dwk
Seek and ye shall find. quaere et invenies.
"Simplicity does not precede complexity, but follows it." -- Alan Perlis
"Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
"The only real mistake is the one from which we learn nothing." -- John Powell
Other boards: DaniWeb, TPS
Unofficial Wiki FAQ: cpwiki.sf.net
My website: http://dwks.theprogrammingsite.com/
Projects: codeform, xuni, atlantis, nort, etc.
If you really needed this type of functionality, you could always look into boost's assignment library. This allows you to write code like:
Code:array<int,4> a = list_of(1)(2)(3)(4).to_array( a );
A lot of boost's stuff seems to be template magic -- so at a guess, I'd say it's probably reasonably efficient at runtime, but inefficient for compilation time.
Erm . . . maybe it is inefficient. doubt about boost/multi_array's efficiency [Archive] - CodeGuru Forums
dwk
Seek and ye shall find. quaere et invenies.
"Simplicity does not precede complexity, but follows it." -- Alan Perlis
"Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
"The only real mistake is the one from which we learn nothing." -- John Powell
Other boards: DaniWeb, TPS
Unofficial Wiki FAQ: cpwiki.sf.net
My website: http://dwks.theprogrammingsite.com/
Projects: codeform, xuni, atlantis, nort, etc.
Well the container type isn't really important, so I don't think there is an efficiency factor here. You can do the same thing with a vector if you want:Code:vector<int> v = list_of(1)(2)(3)(4).to_container( v );Yeah, it takes some getting used to. If you really want to make your brain go crazy for a couple hours, try and follow how the boost developers implement this. It's pretty crazy.Holy smokes! That looks to weird for my tastes.
For the most part, I think its greatest usefulness is in initializing maps. For example:Code:const map<string,int> dayOfWeekLookup = (map_list_of ("monday", 0) ("tuesday", 1) ("wednesday", 2) ("thursday", 3) ("friday", 4) ("saturday", 5) ("sunday", 6));
This would probably be better if it returned a vector...
Code:#include <iterator> #include <iostream> using namespace std; template < typename Type > struct block { block( size_t capacity = 0 ) : data( new Type[ capacity ] ), size( 0 ), capacity( capacity ) { } block( const block& rhs ) : data( const_cast< block& >( rhs ).orphan( ) ), size( rhs.size ), capacity( rhs.capacity ) { } block& operator , ( Type const& value ) { if( size + 1 > capacity ) { Type* saved = data; try { data = new Type[ capacity = capacity + 1 << 1 ]; } catch( ... ) { delete [ ] saved; throw; } copy( saved, saved + size, data ); delete [ ] saved; } data[ size++ ] = value; return *this; } Type* orphan( void ) { Type* saved = data; data = 0; return saved; } inline operator Type* ( void ) { return orphan( ); } virtual ~block( void ) { delete [ ] data; } protected: Type* data; size_t size, capacity; }; int main( void ) { int* array = ( block< int >( ), 1, 2, 3 ); copy( array, array + 3, ostream_iterator< int, char >( cout, "\n" ) ); return 0; }
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
This should be more resilient to exceptions.
Actually, this should use `std::swap_ranges' just in case there exists a non-throwing swap algorithm for the relevant type.
Soma
Code:block & operator , (Type const & value) { if(size + 1 > capacity) { std::size_t new_capacity((capacity + 1) << 1); Type * work(new Type[new_capacity]); std::copy(data, data + size, work); std::swap(data, work); capacity = new_capacity; delete[] work; } data[size++] = value; return *this; }
Last edited by phantomotap; 06-08-2009 at 11:39 PM. Reason: added the obvious suggestion
You're not catching the possible bad_alloc (or whatever other) exception at the point of allocation, though, which would result in a memory leak (in 'saved'). Come to think of it, an exception could occur within std::copy (not with POD's, though), so that should really be in a try block, as well.
Last edited by Sebastiani; 06-09-2009 at 12:17 AM. Reason: clarification
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
I guess I could have simplified it by using std::auto_ptr.
EDIT:Code:#include <memory> #include <iterator> #include <iostream> using namespace std; template < typename Type > struct block { block( size_t capacity = 0 ) : data( new Type[ capacity ] ), size( 0 ), capacity( capacity ) { } block& operator , ( Type const& value ) { if( size + 1 > capacity ) { auto_ptr< Type > saved = data; data.reset( new Type[ capacity = capacity + 1 << 1 ] ); copy( saved.get( ), saved.get( ) + size, data.get( ) ); } data.get( )[ size++ ] = value; return *this; } inline operator Type* ( void ) { return data.release( ); } protected: auto_ptr< Type > data; size_t size, capacity; }; int main( void ) { int* array = ( block< int >( ), 1, 2, 3 ); copy( array, array + 3, ostream_iterator< int, char >( cout, "\n" ) ); return 0; }
@Soma: I didn't incorporate any of the changes you suggested yet simply because I wasn't exactly sure what you were getting at.
Last edited by Sebastiani; 06-09-2009 at 12:45 AM.
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
I'm not catching any allocation related exception because I don't care anything about it. (It is the correct approach, not catching an exception when you can't do anything useful with it.) If `operator new []' raises an exception construction never happens and no leak occurs. If a constructor raises an exception, after the allocation succeeds, a conformant compiler will "unwind" the fully constructed object by calling the destructor for each object and freeing the allocated memory. (It only becomes the programmers responsibility after every object in the array is fully constructed.)You're not catching the possible bad_alloc (or whatever other) exception at the point of allocation, though, which would result in a memory leak (in 'saved').
This can't be helped without writing a good deal of code. (You can write an exception neutral version in the face of a copy constructor that throws, but most programmers will refuse to pay the high cost associated with such an implementation.) The best bet is to use `std::swap_ranges' and hope it eventually calls a swap method with "Koenig Lookup" enabled. (This, last I looked, isn't mandated by the standard.) If that is the case this implementation is almost as good as it gets. (Unless the implementation uses some insane hack to bypass construction without throwing in the case of an error.) You could of course use a smart pointer that works with arrays to strengthen the exception guarantees for the other case.Come to think of it, an exception could occur within std::copy (not with POD's, though), so that should really be in a try block, as well.
That isn't simplified. It is horribly broken. (You must never use an array with `std::auto_ptr<???>'.) It also only serves to hide the problem. If the allocation fails, which as you've indicated is a problem with very real potential, the compiler still has to do the above referenced "magic"--lacking a better work--before the assignment to the `std::auto_ptr<Type>' instance.I guess I could have simplified it by using std::auto_ptr.
My version is exception neutral in the face of a non-throwing copy constructor. (With the additional suggestion it is exception neutral in the face of a copy constructor that can throw an exception.) It can be made exception safe with a simple smart pointer. Your variation is not exception neutral and can't be made exception neutral without a complete shift in the implementation. It isn't exception safe even in the case of a smart pointer.I didn't incorporate any of the changes you suggested yet simply because I wasn't exactly sure what you were getting at.
Soma
Of course, I was totally overlooking the fact that 'data' was protected by the destructor from leaking. The std::auto_ptr/array problem slipped my mind, as well. Long night, I guess.
At any rate, a more orthogonal design altogether might be:
Code:#include <list> #include <vector> #include <iterator> #include <iostream> using namespace std; template < typename Type > struct values { values( void ) { } values( values const& rhs ) { data.swap( const_cast< values& >( rhs ).data ); } values& operator , ( Type const& value ) { data.push_back( value ); return *this; } template < typename Container > inline operator Container( void ) { return Container( data.begin( ), data.end( ) ); } protected: list< Type > data; }; int main( void ) { vector< int > array = ( values< int >( ), 1, 2, 3 ); copy( array.begin( ), array.end( ), ostream_iterator< int, char >( cout, "\n" ) ); return 0; }
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
Considering that all the containers have a specialized swap an overload/specialization is in order with a slightly different interface.
Soma
Code:std::vector<int> vi; {assigner(vi, 3) /* possibly construct an assign_to<???> */, 1, 2 3};Code:std::list<int> li; {assigner(li, 3), 1, 2 3}; // ignore param2(3)Code:int * ai; {assigner(ai, 3), 1, 2 3};
phantomotap:
Sebastiani points out the exception safety missing from that example, but here's another way you could add it:
It's a lot nicer when if an exception is thrown it doesn't get caught at a dozen or so different levels, and extraneous catch-all statements are definitely best avoided where possible. Fortunately it requires roughly the same number of lines to make a nested class that does what we need. (D makes this approach even easier FTW!)Code:block & operator , (Type const & value) { if (size + 1 > capacity) { std::size_t new_capacity((capacity + 1) << 1); struct Dummy { Type *p; Dummy(int c) : p(new Type[c]) {} ~Dummy() { delete[] p; } } d(new_capacity); std::copy(data, data + size, d.p); std::swap(data, d.p); capacity = new_capacity; } data[size++] = value; return *this; }
I must say, I've never used the comma operator before though.
I'd probably just derive from std::vector as well.
My homepage
Advice: Take only as directed - If symptoms persist, please see your debugger
Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"
phantomotapSebastiani points out the [...] from that examplehere's another way you could add itIt's a lot nicer when if an [...] at a dozen or so different levelsI honestly can't figure out if you are trying to point something out to me or Sebastian. You hailed me, but you've not added anything to the discussion. You've only reiterated bits we've said and I'm not sure what that has to do with either of us. If you were offering something to me, you'll have to be explicit 'cause I don't get it.it requires roughly the [...] class that does what we need
Still, you did add, after a fashion, a smart pointer that works with arrays. I hadn't thought of using a nested class to bypass the work. That was a good bit of sorcery.
I don't see why. With an almost negligible change in the interface you can bypass additional copies mandated by the assignment and possibly avoid allocation. Or do you intend a different interface?I'd probably just derive from std::vector as well.
Soma