I have the following code that intends to create an array, but without default initialization of its objects. I would like to forward perfectly to placement new, which seems to happen, but I find that the objects' destructor is called inside the emplace function.
#include <iostream>
#include <memory> // std::uninitialized_copy, std::allocator...
#include <utility> // std::move...
#include <bitset>
struct Int {
int i;
Int ( ) : i ( -1 ) { std::cout << "default constructed\n"; }
Int ( const int i_ ) : i ( i_ ) { std::cout << i << " constructed\n"; }
Int ( Int && int_ ) : i ( std::move ( int_.i ) ) { std::cout << i << " move constructed\n"; }
Int ( const Int & int_ ) : i ( int_.i ) { std::cout << i << " copy constructed\n"; }
~Int ( ) { std::cout << i << " destructed\n"; i = -1; }
};
template <typename T, size_t S = 64>
class NoInitArray {
std::bitset<S> m_used;
T *m_array = reinterpret_cast < T* > ( ::operator new ( sizeof ( T ) * S ) );
public:
T const &operator [ ] ( const size_t idx_ ) const {
return m_array [ idx_ ];
}
NoInitArray ( ) { }
~NoInitArray ( ) {
for ( size_t idx = 0; idx < S; ++idx ) {
if ( m_used [ idx ] ) {
reinterpret_cast< const T* > ( m_array + idx )->~T ( );
}
}
}
template<typename ...Args>
void emplace ( const size_t idx_, Args &&... value_ ) {
std::cout << "start emplace\n";
m_used [ idx_ ] = 1;
new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... );
std::cout << "end emplace\n";
}
};
int main ( ) {
NoInitArray<Int> nia;
nia.emplace ( 0, 0 );
nia.emplace ( 1, 1 );
std::cout << nia [ 1 ].i << std::endl;
nia.emplace ( 2, 2 );
return 0;
}
The result of running this program is as follows:
start emplace
0 constructed
0 move constructed
0 destructed
end emplace
start emplace
1 constructed
1 move constructed
1 destructed
end emplace
1
start emplace
2 constructed
2 move constructed
2 destructed
end emplace
0 destructed
1 destructed
2 destructed
It shows that the objects are constructed once and destructed twice (which obviously is UB), once inside the emplace function, and then once at destruction of the NoInitArray.
The question is "Why is the destructor of my Int object called inside the emplace function"?
Compiler, latest Clang/LLVM on Windhoze.
EDIT1: I've added move and copy constructors to the Int struct, now the count matches, i.e. 2 constructions and 2 destructions.
EDIT2: Changing the Placement New line from new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... ); to new ( m_array + idx_ ) T ( value_ ... ); avoids the superfluous construction/destruction, without the need for a move constructor.
EDIT3: Just for future readers. As per above, the ~NoInitArray() leaks memory. Calling delete on m_array is bad news as well as this calls (in Clang/LLVM) the destructor of m_array [ 0 ] (but as far as I've understood now, that is in no way guaranteed, i.e. UB). std::malloc/std::free seems to be the way to go, but some say that if you do that all hell will break lose, and one may lose a leg.
"It shows that the objects are constructed once and destructed twice" is not true. The output X move constructed should be included as one construction so the constructions are twice.
The line
new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... );
should be
new ( m_array + idx_ ) T ( std::forward<Args&&> ( value_ )... );
std::forward<T>(value_) calls the constructor when T=Int, and this temporary object is moved, so there is an extra move constructor call.
EDIT
In your edit 2 you replace the line without std::forward anymore. In this case, OK, but the differences emerge when you call the emplace like this
nia.emplace ( 0, Int(0) );
Without std::forward, new T(value_...) would call the copy constructor, while new T(std::forward<Args&&>(value_)...) would call the move constructor.
EDIT-2
It should be new T(std::forward<Args>(value_)...). Thanks to #Constantin Baranov.
I think the constructor and destructor are called in the step: std::forward<T> ( value_ ) in new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... ).
The std::forward<T>(value_) will create a temp value T.
Related
Here is the code from the book
LargeType randomItem1( const vector<LargeType> & arr )
{
return arr[ randomInt( 0, arr.size( )-1)];
}
const LargeType & randomItem2( const vector<LargeType> & arr )
{
return arr[ randomInt( 0, arr.size( )-1)];
}
vector<LargeType> vec;
...
LargeType item1 = randomItem1( vec );// copy
LargeType item2 = randomItem2( vec );// copy
const LargeType & item3 = randomItem2( vec ); // no copy
vector<int> partialSum( const vector<int> & arr )
{
vector<int> result( arr.size( ) );
result[ 0 ] = arr[ 0 ];
for( int i = 1; i < arr.size( ); ++i )
{
result[ i ] = result[ i-1]+ arr[ i ];
}
return result;
}
vector<int> vec;
...
vector<int> sums = partialSum( vec ); // Copy in old C++; move in C++11
The book says LargeType randomItem1( const vector<LargeType> & arr ) does not call move semantics while vector<int> partialSum( const vector<int> & arr ) does. Why is this happening?
I understand that return arr[ randomInt( 0, arr.size( )-1)]; is an lvalue since arr itself is reference of object but isn't result an object too? the book says return result is temporary, however it is declared at line 3 at second code box.
want to know why return result is temporary even if it is declared and have name.
The fucntion randomItem1 does not own arr, which means it is not allowed to move arr[ randomInt( 0, arr.size( )-1)] out of the function.
In partialSum the function owns result so it is free to move it out of the function once the function ends.
The rule is that all function local variables can be treated as rvalues for the purpose of the return statement and only are considered an lvalue if no constructor can be found when considered as an rvalue.
In addition to what NathanOliver said, vector<int> sums = partialSum( vec ); may result in neither copy nor move because of copy elision.
I am writing an app to parse lines in a text file. The problem is that I need to be able to load different routines depending on a variable set at run-time. I can not change the format of the incoming file.
int intFormat = 1; //Loaded from INI file
void __fastcall TForm1::Button1Click(TObject *Sender) {
myFileConverstion *myFC;
switch(intFormat) {
case 1:
myFC = new FileConverstionCompanyA();
case 2:
myFC = new FileConverstionCompanyB();
}
myFileConverstion->Execute("fileName");
}
Within ->Execute(), I would be calling private (or protected) methods to do the parsing. There are some of the methods that could be used across all formats, too.
What would be the best OOP way to do this?
Create a virtual object i.e: myFileConverstion? Then inherit from that for the CompanyA, B, C, etc.
write myFileConverstion with all the common methods (private/protected) and a virtual Execute(). Then just change the Execute() internals for the various "companies"?
I'm looking for some guidance.
Haven't really tried anything yet, I'm in the planning stage.
There would also be the possibility to realize the whole thing with std:.function by inserting them into some kind of lookup map. Here is some example:
#include <functional>
#include <iostream>
#include <unordered_map>
class FileConverter
{
using convert_engine_t = std::function< bool( const std::string& ) >;
std::unordered_map< size_t, convert_engine_t > engines;
convert_engine_t *activeEngine { nullptr };
public:
template < class T >
auto addEngine( size_t id, T && routine ) -> void
{
engines.emplace( id, std::forward< T >( routine ) );
}
auto setActiveEngine( size_t id ) -> bool
{
const auto iterFound = engines.find( id );
if ( iterFound == engines.end() )
return false;
activeEngine = &iterFound->second;
return true;
}
auto convert( const std::string fileName ) -> bool
{
if ( !activeEngine || !( *activeEngine ) )
return false;
return ( *activeEngine )( fileName );
}
};
int main()
{
struct MyConvertingEngineA
{
auto operator()( const auto& fn ) {
std::cout << "Doing A" << std::endl; return true;
}
};
auto myConvertingEngineB = []( const auto& fn ) {
std::cout << "Doing B" << std::endl; return true;
};
FileConverter myFC;
myFC.addEngine( 1, MyConvertingEngineA() );
myFC.addEngine( 2, std::move( myConvertingEngineB ) );
myFC.addEngine( 8, []( const auto& fn ){ std::cout << "Doing C" << std::endl; return true; } );
myFC.setActiveEngine( 1 );
myFC.convert( "MyFileA1" );
myFC.convert( "MyFileA2" );
myFC.setActiveEngine( 2 );
myFC.convert( "MyFileB" );
myFC.setActiveEngine( 8 );
myFC.convert( "MyFileC" );
myFC.setActiveEngine( 7 ); // Will fail, old engine will remain active
return 0;
}
Output:
Doing A
Doing A
Doing B
Doing C
A few explanations about the code:
The addEngine function uses templates with a forwarding reference and
perfect forwarding to provide the widest possible interface.
Engines are copied or moved here, depending on the type of reference passing. The engines are passed in form of "callable objects".
Different types like functors or lambdas can be added.
Even (as in the example) generic lambdas can be passed (auto parameter) as long as the function signature of of std::function is fulfilled.
This saves another redundant specification of the string type.
If you have large and complex engines, use a separate class instead of a lambda to keep the local scope small
Shared parser-functionality could also be passed to the respective engines via smart pointer if you don't want to have any inheritance.
class EngineA
{
std::shared_ptr< ParserCore > parserCore;
public:
EngineA( std::shared_ptr< ParserCore > parserCoreParam ) :
parserCore( std::move( parserCoreParam ) )
{}
auto operator()( const auto& fn ) {
std::cout << "Doing A" << std::endl; return true;
// -> parserCore->helperFuncForABC() ....;
}
};
Consider this unit test:
std::bitset<8> temp( "11010100" );
reverseBitSet( temp );
CPPUNIT_ASSERT( temp == std::bitset<8>( "00101011" ) );
This implementation works:
template<size_t _Count> static inline void reverseBitSet( std::bitset<_Count>& bitset )
{
bool val;
for ( size_t pos = 0; pos < _Count/2; ++pos )
{
val = bitset[pos];
bitset[pos] = bitset[_Count-pos-1];
bitset[_Count-pos-1] = val;
}
}
While this one does not:
template<size_t _Count> static inline void reverseBitSet( std::bitset<_Count>& bitset )
{
for ( size_t pos = 0; pos < _Count/2; ++pos )
{
std::swap( bitset[pos], bitset[_Count-pos-1] );
}
}
Result is "11011011" instead of "00101011"
Why is swap doing it wrong?
This:
std::swap( bitset[pos], bitset[_Count-pos-1] );
should actual fail to compile. operator[] for a std::bitset doesn't return a reference, it returns a proxy object. That proxy object isn't an lvalue, so it cannot bind to the T& in std::swap. I'm assuming the fact that it compiles at all means that you're using MSVC which has an extension that allows binding temporaries to non-const references - at which point you're probably just swapping the proxies and not what the proxies are actually referring to.
Side-note: The name _Count is reserved by the standard, as is any other name which begins with an _ followed by a capital letter.
Assume I have class MyClass
class MyClass
{
public:
MyClass( std::string str ) : _str(str) {}
void SetPosition ( int i ) { _pos = i; }
std::string _str;
int _pos;
};
namespace std
{
template<> struct hash<shared_ptr<MyClass>>
{
size_t operator()( const shared_ptr<MyClass> & ptr ) const
{
return hash<string>()( ptr->_str ) + hash<int>()( ptr->_pos );
}
};
}
When using std::vector, I was able to do this:
std::string str = "blah";
auto ptr = std::make_shared<MyClass>( str );
std::vector<std::shared_ptr<MyClass>> vector;
vector.push_back( ptr );
ptr->SetPosition ( std::addressof( vector.back() ) - std::addressof( vector[0] ) );
std::cout << ptr->_str << " is at " << ptr->_pos << std::endl;
In order to calculate where in the vector, my object pointer was placed.
However, If I want to use std::unordered_set (which I do), then:
std::string str = "blah";
auto ptr = std::make_shared<MyClass>( str );
std::unordered_set<std::shared_ptr<MyClass>> set;
auto res = set.insert( ptr );
ptr->SetPosition ( std::addressof( res.first ) - std::addressof( set[0] ) );
std::cout << ptr->_str << " is at " << ptr->_pos << std::endl;
Will not work.
Neither will
std::addressof( set.begin() );
Nor will,
std::addressof( set.begin().first );
or any other way I try to use the front iterator.
Does this make sense? Or should I rely on set.size() and assume that my pointer was inserted at the end?
Is there any way to safely get the position where that pointer was inserted using something similar to the above code?
unordered_set, like the name implies, is unordered. You can keep track of the position of your elements in a vector, because as long as you don't erase anything, they won't change places. But that's not true of unordered_set. For instance, on my implementation, here's what printing all the elements in order after every insert would yield:
std::unordered_set<int> s;
s.insert(0); // 0
s.insert(1); // 1 0
s.insert(2); // 2 1 0
s.insert(3); // 3 2 1 0
...
s.insert(22); // 22 0 1 2 3 ... 19 20 21
...
s.insert(48); // 48 47 46 45 ... 22 0 1 2 3 4 ... 21
So what I'm trying to say is order is definitely not something that makes sense for you to rely on.
With your vector, however, you can do much better in terms of setting position:
vector.push_back(ptr);
ptr->SetPosition(vector.size() - 1);
explicit list(
const A& Al = A( )
);
explicit list(
size_type n,
const T& v = T( ),
const A& Al = A( )
);
list(
const list& x
);
list(
const_iterator First,
const_iterator Last,
const A& Al = A( )
);
#include <list>
using namespace std;
list<Node> my_list;
int index = 0;
for ( list<Node>::iterator cursor = my_list.begin();
it!= my_list.end(); ++ cursor, ++ index ) {
cout << "index: " << index << “ value: “ << cursor->data() << endl;
}
At least based on what you have here, the problem isn't with how you traverse the list -- it's with using a list at all. You're asking for random access to the data, which means you should probably be using something like a vector or a deque instead of a list.
I really can't tell what this is trying to do, but you have a possible segfault in your inner loop:
for ( cursor = head_ptr; cursor !=NULL ||count<i; cursor=cursor->link() )
{
count++;
}
Your termination condition indicates that if count < i, you would keep looping even if cursor == NULL; when cursor=cursor->link() executes, you would try to dereference NULL.
Perhaps you meant cursor !=NULL && count<i ?