Currently I do the following:
// float *c_array = new float[1024];
void Foo::foo(float *c_array, size_t c_array_size) {
//std::vector<float> cpp_array;
cpp_array.assign(c_array, c_array + c_array_size);
delete [] c_array;
}
How can I optimize this assigning? I would like not to perform elementwise copy but just swap pointers.
The current std::vector doesn't provide any capability or interface to take ownership of previously allocated storage. Presumably it would be too easy to pass a stack address in by accident, allowing more problems than it solved.
If you want to avoid copying into a vector, you'll either need to use vectors through your entire call chain, or do it the C way with float[] the entire time. You can't mix them. You can guaranteed that &vec[0] will be equivalent to the C-array though, fully contiguous, so using vector in the whole program may be feasible.
Currently, the std::vector interface does not possess the capacity to move from or swap with anything except another std::vector.
The only way to do it would be to create a custom allocator.
Write an allocator class that you can initialise with your array.
Instantiate the vector with the allocator as an argument.
Unlikely it's possible - it's quite dangerous, because std::vector doesn't know how the memory was allocated and how it should be freed.
If it's possible, you may replace original allocation with creation of std::vector of correct size. It uses contiguous memory area, so it can replace manually allocated buffer.
It is possible with the use of a custom allocator. I checked on godbolt.org with clang and gcc. To me, it looks a bit of an ugly hack – but it works at least as a proof of concept.
Of course, you have to take care of the lifetime of the array for yourself.
#include <vector>
#include <iostream>
// custom allocator
template <typename T>
class my_allocator {
private:
T* const addr;
public:
template <typename U>
struct rebind {
typedef my_allocator<U> other;
};
//provide the required no-throw constructors / destructors:
constexpr my_allocator(T* addr_) : addr(addr_) { };
constexpr my_allocator(const my_allocator<T>& rhs) : addr(rhs.addr) { };
template <typename U>
my_allocator(const my_allocator<U>& rhs, T* addr_) : addr(addr_) { };
~my_allocator() { };
//import the required typedefs:
using value_type=T;
using pointer=T*;
using reference=T&;
using const_pointer=const T*;
using const_reference=const T&;
using size_type=size_t;
using difference_type=ptrdiff_t;
constexpr pointer allocate(size_type n, const void * = 0) {
pointer t=addr;
std::cout
<< " used my_allocator to allocate at address "
<< t << " (+)" << std::endl;
return addr;
}
constexpr void deallocate(void* p, size_type) {
if (p) {
std::cout
<< " used my_allocator to deallocate at address "
<< p << " (-)" <<
std::endl;
}
}
template< class U, class... Args >
void construct( U* p, Args&&... args ) {
// avoids initialisation of the elements.
std::cout << "Contruct called" << std::endl;
}
};
// helper function for easy useage
template<typename T>
const std::vector<T, my_allocator<T> > CreateVectorFromArray(T* array, int size) {
const my_allocator<T> alloc=my_allocator<T>(array);
std::vector<int, my_allocator<int> > vecAll(size, my_allocator<int>(array));
return vecAll;
}
template<typename T>
using element_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<T&>()))>;
template<typename AR>
auto CreateVectorFromArrayAr(AR& array) {
using T=element_type_t<AR>;
const my_allocator<T> alloc=my_allocator<T>(array);
std::vector<T, my_allocator<T> > vecAll(sizeof(array)/sizeof(array[0]), my_allocator<T>(array));
return vecAll;
}
int main() {
int array[]={0,1,2,3,4,5,6,7,8,9};
std::cout << "Array: " << &array[0] << " " << array[0] << " " << array[1]<< " " << array[2] << std::endl;
auto vecAll=CreateVectorFromArray(array, sizeof(array)/sizeof(array[0]));
auto vec3=CreateVectorFromArrayAr(array);
std::cout << "Vector: " << &vecAll[0] << " " << vecAll[0] << " " << vecAll[1]<< " " << vecAll[2] << std::endl;
std::cout << "Array: " << &array[0] << " " << array[0] << " " << array[1] << " " << array[2] << std::endl;
std::cout << "vec3: " << &vec3[0] << " " << vec3[0] << " " << vec3[1] << " " << vec3[2] << std::endl;
std::cout << "sizeof(vecAll)=" << sizeof(vecAll) << std::endl;
std::cout << "sizeof(void*)=" << sizeof(void*) << std::endl;
return 0;
}
Related
When I trace calls to the member functions of my custom allocator class,
as used by an STL container,
I notice some strange behavior: there is a call to my allocator class's
destructor that isn't matched by any earlier constructor call.
How is that possible?
Here's my code:
/*
g++ -pedantic -W -Wall -Werror screwy_allocator_example.cc -o screwy_allocator_example
*/
#include <iostream>
#include <vector>
namespace {
template<class T>
class MyAllocator {
public:
using value_type = T;
template<typename U> struct rebind { using other = MyAllocator<U>; };
MyAllocator() {
std::cout << " in MyAllocator ctor(this="<<this<<")" << std::endl;
std::cout << " out MyAllocator ctor(this="<<this<<")" << std::endl;
}
~MyAllocator() {
std::cout << " in MyAllocator dtor(this="<<this<<")" << std::endl;
std::cout << " out MyAllocator dtor(this="<<this<<")" << std::endl;
}
template<typename From>
MyAllocator(const From &from) {
std::cout << " in MyAllocator copy ctor("
<< "this="<<this<<", &from="<<(void*)&from<<")" << std::endl;
std::cout << " out MyAllocator copy ctor("
<< "this="<<this<<", &from="<<(void*)&from<<")" << std::endl;
}
template<typename From>
MyAllocator &operator=(const From &from) {
std::cout << " in MyAllocator operator=("
<< "this="<<this<<", &from="<<(void*)&from<<")" << std::endl;
std::cout << " out MyAllocator operator=("
<< "this="<<this<<", &from="<<(void*)&from<<")" << std::endl;
return *this;
}
T *allocate(size_t n) {
std::cout << " in MyAllocator::allocate("
<< "this="<<this<<", n="<<n<<")" << std::endl;
// assume n*sizeof(T) doesn't overflow
T *answer = (T*)std::malloc(n * sizeof(T));
// assume answer!=nullptr
std::cout << " out MyAllocator::allocate(this="<<this<<", n="<<n<<")"
<< ", returning "<<(void*)answer << std::endl;
return answer;
}
void deallocate(T *p, size_t n) {
std::cout << " in MyAllocator::deallocate("
<< "this="<<this<<", p="<<(void*)p<<", n="<<n<<")" << std::endl;
std::free(p);
std::cout << " out MyAllocator::deallocate("
<< "this="<<this<<", p="<<(void*)p<<", n="<<n<<")" << std::endl;
}
template<typename U> bool operator==(const MyAllocator<U> &) const
{ return true; }
template<typename U> bool operator!=(const MyAllocator<U> &) const
{ return false; }
}; // class MyAllocator<T>
} // namespace
int main(const int, char**const) {
std::cout << "in main" << std::endl;
{
std::cout << " constructing my_allocator" << std::endl;
MyAllocator<double> my_allocator;
std::cout << " constructed my_allocator" << std::endl;
{
std::cout << " constructing v(my_allocator)" << std::endl;
std::vector<double, MyAllocator<double>> v(my_allocator);
std::cout << " constructed v(my_allocator)" << std::endl;
std::cout << " pushing one item onto v" << std::endl;
v.push_back(3.14);
std::cout << " pushed one item onto v" << std::endl;
std::cout << " destructing v(my_allocator)" << std::endl;
}
std::cout << " destructed v(my_allocator)" << std::endl;
std::cout << " destructing my_allocator" << std::endl;
}
std::cout << " destructed my_allocator" << std::endl;
std::cout << "out main" << std::endl;
return 0;
}
Here's the output (it's the same for -std=c++11, -std=c++14, -std=c++17, -std=c++2a):
in main
constructing my_allocator
in MyAllocator ctor(this=0x7ffe4cee5747)
out MyAllocator ctor(this=0x7ffe4cee5747)
constructed my_allocator
constructing v(my_allocator)
constructed v(my_allocator)
pushing one item onto v
in MyAllocator::allocate(this=0x7ffe4cee5720, n=1)
out MyAllocator::allocate(this=0x7ffe4cee5720, n=1), returning 0x55890a41d2c0
pushed one item onto v
destructing v(my_allocator)
in MyAllocator::deallocate(this=0x7ffe4cee5720, p=0x55890a41d2c0, n=1)
out MyAllocator::deallocate(this=0x7ffe4cee5720, p=0x55890a41d2c0, n=1)
in MyAllocator dtor(this=0x7ffe4cee5720)
out MyAllocator dtor(this=0x7ffe4cee5720)
destructed v(my_allocator)
destructing my_allocator
in MyAllocator dtor(this=0x7ffe4cee5747)
out MyAllocator dtor(this=0x7ffe4cee5747)
destructed my_allocator
out main
Notice that there were two calls to the dtor, but only one call to the ctor:
first the MyAllocator ctor got called, with this=0x7ffe4cee5747
then a second mystery MyAllocator object appeared at this=0x7ffe4cee5720,
was used, and then was destructed (without ever having been constructed!?)
then the first MyAllocator object at this=0x7ffe4cee5747
(the one that was constructed) gets destructed as expected.
What's going on here?
It seems the simplest explanation would be that I'm just forgetting
about some flavor of constructor that the compiler generates for me.
Is that it?
If not, here are some other thoughts.
I know that prior to c++11, allocator objects were required to be "stateless".
I'm not sure precisely what that means, but perhaps it could be argued
that it implies that, prior to c++11, the compiler could be justified
in playing games like making bytewise copies of allocator objects,
skipping the constructor calls?
But, regardless, in c++11 and later,
allocators are supposedly allowed to have state, right?
Given that, I don't see how it can make any sense for the constructor call
to be skipped.
Given this strange behavior,
it seems to me that I have no choice but to implement
my allocator using the pre-c++11 restrictions:
that is, the allocator must be nothing more than
a stateless handle to some other resource.
That's what I'm doing, successfully, but I'd like to understand why this
is necessary.
When compiling this code with -Waddress:
#include <iostream>
#include <memory>
#include <string.h>
template <typename T, void (*func)(T*) = nullptr>
struct Caller {
Caller(T* ptr = nullptr)
{
std::cout
<< "Creating caller " << ptr
<< ", is function " << std::is_function<decltype(func)>()
<< ", is null " << std::is_null_pointer<decltype(func)>()
<< ", function is " << func
<< std::endl;
if (func)
{
std::cout << "Running for " << ptr << " func " << func << std::endl;
func(ptr);
}
}
};
void free_char(char *c) { free(c); }
int main() {
Caller<char, free_char>(strdup("Test"));
Caller<const char>("Test2");
return 0;
}
it will fail with:
/tmp/foo.cpp: In instantiation of ‘Caller<T, func>::Caller(T*) [with T = char; void (* func)(T*) = free_char]’:
/tmp/foo.cpp:36:40: required from here
/tmp/foo.cpp:13:33: warning: the address of ‘void free_char(char*)’ will never be NULL [-Waddress]
A workaround is using something like if (auto f = func) f(ptr); but i'd like to have something that is statically checked at compile time.
This solution mentions the usage of template specialization, but a part that here we're handling a struct, this is a case where i'd like to use static template checks.
How about simply providing a no-op function by default instead of a null pointer? This gets rid of the if altogether and makes the code cleaner in general.
template<typename T>
void no_op(T*) {}
template <typename T, void (*func)(T*) = no_op<T>>
struct Caller {
static_assert(func != nullptr, "don't pass nullptr");
Caller(T* ptr = nullptr)
{
std::cout
<< "Creating caller " << ptr
<< ", is function " << std::is_function<decltype(func)>()
<< ", is null " << std::is_null_pointer<decltype(func)>()
<< ", function is " << func
<< std::endl;
std::cout << "Running for " << ptr << " func " << func << std::endl;
func(ptr);
}
};
I'd like to take out members of a temporary without unnecessary moving or copying.
Suppose I have:
class TP {
T _t1, _t2;
};
I'd like to get _t1, and _t2 from TP(). Is it possible without copying/moving members?
I've tried with tuples and trying to "forward" (I don't think it's possible) the members, but the best I could get was a move, or members dying immediately.
In the following playground using B::as_tuple2 ends up with members dying too soon, unless the result is bound to a non-ref type, then members are moved. B::as_tuple simply moves is safe with auto on client side.
I suppose this should be technically possible, since the temporary dies immediately, and the member do die while they could bound to variables on the calling site (Am I wrong?), and structured binding of a similar struct works as intended.
Is it possible to extend/pass life of the member onto an outside variable, or elide the move/copy? I need it with c++14 version, but I couldn't get it to work on c++17 either, so I am interested in both.
Playground:
#include <tuple>
#include <iostream>
using std::cout;
class Shawty {
/**
* Pronounced shouty.
**/
public:
Shawty() : _id(Shawty::id++) {cout << _id << " ctor\n"; }
Shawty(Shawty && s) : _id(Shawty::id++) { cout << _id << " moved from " << s._id << "\n"; }
Shawty(const Shawty & s) : _id(Shawty::id++) { cout << _id << " copied from " << s._id << "\n"; }
Shawty& operator=(Shawty && s) { cout << _id << " =moved from " << s._id << "\n"; return *this;}
Shawty& operator=(Shawty & s) { cout << _id << " =copied from " << s._id << "\n"; return *this;}
~Shawty() {cout << _id << " dtor\n"; }
int _id;
static int id;
};
int Shawty::id = 0;
class B {
public:
auto as_tuple() && {return std::make_tuple(std::move(_s1), std::move(_s2));}
auto as_tuple2() && {return std::forward_as_tuple(std::move(_s1), std::move(_s2));}
private:
Shawty _s1, _s2;
};
struct S {
Shawty _s1, _s2;
};
int main() {
std::cout << "----------\n";
auto [s1, s2] = B().as_tuple2();
std::cout << "---------\n";
auto tpl1 = B().as_tuple2();
std::cout << "----------\n";
std::tuple<Shawty, Shawty> tpl2 = B().as_tuple2();
std::cout << "----------\n";
std::cout << std::get<0>(tpl1)._id << '\n';
std::cout << std::get<1>(tpl1)._id << '\n';
std::cout << std::get<0>(tpl2)._id << '\n';
std::cout << std::get<1>(tpl2)._id << '\n';
std::cout << s1._id << '\n';
std::cout << s2._id << '\n';
std::cout << "--struct--\n";
auto [s3, s4] = S{};
std::cout << s3._id << '\n';
std::cout << s4._id << '\n';
std::cout << "----------\n";
return 0;
}
No. It is not possible to extend the lifetime of more than one member beyond the lifetime of the super object.
So, the only way to "get" members without copying is to keep the super object alive, and refer to them:
// member function
auto as_tuple3() & {
return std::make_tuple(std::ref(_s1), std::ref(_s2));
}
// usage
B b;
auto [s1, s2] = b.as_tuple3();
An example of extending lifetime of the object by binding a reference to a single member. Note that this requires the member to be accessible from where the reference is bound (not the case in your example, where the member is private):
auto&& s1 = B{}._s1;
Add support for structured binding to your B type.
class B {
public:
template<std::size_t I, class Self,
std::enable_if_t< std::is_same_v<B, std::decay_t<Self>>, bool> = true
>
friend constexpr decltype(auto) get(Self&& self) {
if constexpr(I==0)
{
using R = decltype(std::forward<Self>(self)._s1)&&;
return (R)std::forward<Self>(self)._s1;
}
else if constexpr(I==1)
{
using R = decltype(std::forward<Self>(self)._s2)&&;
return (R)std::forward<Self>(self)._s2;
}
}
private:
Shawty _s1, _s2;
};
namespace std {
template<>
struct tuple_size<::B>:std::integral_constant<std::size_t, 2> {};
template<std::size_t N>
struct tuple_element<N, ::B>{using type=Shawty;};
}
Test code:
int main() {
std::cout << "----------\n";
{
auto&& [s1, s2] = B();
}
}
output:
----------
0 ctor
1 ctor
1 dtor
0 dtor
Live example.
This is the best I can do. Note that s1 and s2 are references into a lifetime-extended version of B.
First off: I know that it is generally a bad idea to change an object's class, but I'm implementing my own programming language, and it has variables that can contain values of any type, and even change their type at will, so please assume I'm not a beginner not understanding OO basics.
Currently, I implement my variant variables in C. Each one has a pointer to a table of function pointers, containing functions like SetAsInt(), SetAsString() etc., followed by what would be instance variables in C++. All objects are the same size.
When a variable contains a string and someone assigns an Int to it, I manually call the destructor, change the table of function pointers to point to the table used for variadic int values, and then set its int instance variable.
This is a bit hard to maintain, as every time I add a new type, I have to add a new table of function pointers and fill out all the function pointers in it. Structs of function pointers seem to be very badly type-checked, and missing fields don't lead to complaints, so I can easily accidentally forget one pointer in the list and get interesting crashes. Also, I have to repeat all the function pointers that are the same in most types.
I'd like to implement my variadic types in C++ instead, where a lot of this type-checking and inheriting default behaviours is done for me by the compiler. Is there a safe way to do this?
PS - I know I could create a wrapper object and use new to allocate a new object, but I can't have the additional extra allocation overhead for every int variable on the stack.
PPS - The code needs to be portable across Linux, Mac, iOS and Windows for now, but if someone has a standard C++ solution, that would be even better.
PPPS - The list of types is extensible, but predetermined at compile-time. The base layer of my language defines just the basic types, but the host application my language is compiled into adds a few more types.
Usage Example:
CppVariant someNum(42); // Creates it as CppVariantInt.
cout << "Original int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsInt(700); // This is just a setter call.
cout << "Changed int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsDouble(12.34); // This calls destructor on CppVariantInt and constructor on CppVariantDouble(12.34).
cout << "Converted to Double: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl; // GetAsInt() on a CppVariantDouble() rounds, or whatever.
(Imagine that beyond double and int, there would be other types in the future, like strings or booleans, but the caller of GetAsInt()/SetAsInt() shouldn't have to know what it is stored as, as long as it can be converted at runtime)
Here is a solution based on type-erasure, union and template specializations.
I'm not sure it fits your requirements.
Anyway, here is what it gets:
Anything is placed on the dynamic storage
No hierarchy required
You can easily improve it further to reduce the amount of code, but this aims to serve as a base point from which to start.
It follows a minimal, working example based on the intended use in the question:
#include<iostream>
class CppVariant {
union var {
var(): i{0} {}
int i;
double d;
};
using AsIntF = int(*)(var);
using AsDoubleF = double(*)(var);
template<typename From, typename To>
static To protoAs(var);
public:
CppVariant(int);
CppVariant(double);
int getAsInt();
double getAsDouble();
void setAsInt(int);
void setAsDouble(double);
private:
var data;
AsIntF asInt;
AsDoubleF asDouble;
};
template<>
int CppVariant::protoAs<int, int>(var data) {
return data.i;
}
template<>
int CppVariant::protoAs<double, int>(var data) {
return int(data.d);
}
template<>
double CppVariant::protoAs<int, double>(var data) {
return double(data.i);
}
template<>
double CppVariant::protoAs<double, double>(var data) {
return data.d;
}
CppVariant::CppVariant(int i)
: data{},
asInt{&protoAs<int, int>},
asDouble{&protoAs<int, double>}
{ data.i = i; }
CppVariant::CppVariant(double d)
: data{},
asInt{&protoAs<double, int>},
asDouble{&protoAs<double, double>}
{ data.d = d; }
int CppVariant::getAsInt() { return asInt(data); }
double CppVariant::getAsDouble() { return asDouble(data); }
void CppVariant::setAsInt(int i) {
data.i = i;
asInt = &protoAs<int, int>;
asDouble = &protoAs<int, double>;
}
void CppVariant::setAsDouble(double d) {
data.d = d;
asInt = &protoAs<double, int>;
asDouble = &protoAs<double, double>;
}
int main() {
CppVariant someNum(42);
std::cout << "Original int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
someNum.setAsInt(700);
std::cout << "Changed int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
someNum.setAsDouble(12.34);
std::cout << "Converted to Double: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
}
On a lark, I tried using placement new to do this, and I have ... something ... It compiles, it does the job, but I'm not sure if it's an improvement over pure C. Since I can't have a union of C++ objects, I create a CPPVMAX() macro to pass the largest sizeof() of all subclasses as the size to mBuf[], but that's not really pretty either.
#include <iostream>
#include <string>
#include <cmath>
#define CPPVMAX2(a,b) (((a) > (b)) ? (a) : (b))
#define CPPVMAX3(a,b,c) CPPVMAX2((a),CPPVMAX2((b),(c)))
using namespace std;
class CppVariantBase
{
public:
CppVariantBase() { cout << "CppVariantBase constructor." << endl; }
virtual ~CppVariantBase() { cout << "CppVariantBase destructor." << endl; }
virtual int GetAsInt() = 0;
virtual double GetAsDouble() = 0;
virtual void SetAsInt( int n );
virtual void SetAsDouble( double n );
};
class CppVariantInt : public CppVariantBase
{
public:
CppVariantInt( int n = 0 ) : mInt(n)
{
cout << "CppVariantInt constructor." << endl;
}
~CppVariantInt() { cout << "CppVariantInt destructor." << endl; }
virtual int GetAsInt() { return mInt; }
virtual double GetAsDouble() { return mInt; }
virtual void SetAsInt( int n ) { mInt = n; }
protected:
int mInt;
};
class CppVariantDouble : public CppVariantBase
{
public:
CppVariantDouble( double n = 0 ) : mDouble(n)
{
cout << "CppVariantDouble constructor." << endl;
}
~CppVariantDouble()
{
cout << "CppVariantDouble destructor." << endl;
}
virtual int GetAsInt()
{
if( int(mDouble) == mDouble )
return mDouble;
else
return round(mDouble);
}
virtual double GetAsDouble() { return mDouble; }
virtual void SetAsDouble( int n ) { mDouble = n; }
protected:
double mDouble;
};
class CppVariant
{
public:
CppVariant( int n = 0 ) { new (mBuf) CppVariantInt(n); }
~CppVariant() { ((CppVariantBase*)mBuf)->~CppVariantBase(); }
operator CppVariantBase* () { return (CppVariantBase*)mBuf; }
CppVariantBase* operator -> () { return (CppVariantBase*)mBuf; }
protected:
uint8_t mBuf[CPPVMAX3(sizeof(CppVariantBase),sizeof(CppVariantInt),sizeof(CppVariantDouble))];
};
void CppVariantBase::SetAsInt( int n )
{
this->~CppVariantBase();
new (this) CppVariantInt(n);
}
void CppVariantBase::SetAsDouble( double n )
{
this->~CppVariantBase();
new (this) CppVariantDouble(n);
}
int main(int argc, const char * argv[]) {
CppVariant someNum(42);
cout << "Original int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsInt(700); // This is just a setter call.
cout << "Changed int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsDouble(12.34); // This changes the class to CppVariantDouble.
cout << "Converted to Double: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
return 0;
}
I'm trying to create my own string class using std::basic_string<> with a custom allocator. It's seems to be mostly working thanks in large part to other related topics on stackoverflow. But I really want this to be a drop in replacement of std::string. To that end, it needs to assignable to/from std:string. I tried overloading assignment operators and such but I can't seem to get that working.
The end goal here is to be able to log/track memory allocations for strings in existing code by replacing std::string. If there's a better way of doing that, I'd like to hear it as well.
This is an embedded application so my options with 3rd party tools is limited.
Here's a sample app with the code I have already.
dave
#include <iostream>
using namespace std;
namespace mw_allocator_namespace
{
int mw_allocator_space =0;
template <typename T>
class mw_allocator: public std::allocator<T>
{
public:
typedef size_t size_type;
typedef T* pointer;
typedef const T* const_pointer;
template<typename _Tp1>
struct rebind
{
typedef mw_allocator<_Tp1> other;
};
pointer allocate(size_type n, const void *hint=0)
{
pointer p = std::allocator<T>::allocate(n, hint);
mw_allocator_space += n*sizeof(T);
cout << hex << " Alloc: " << n << " : " << n*sizeof(T) << " (" << reinterpret_cast<unsigned long long>(p) << ")" << endl;
return p;
}
void deallocate(pointer p, size_type n)
{
cout << hex << " Dealloc: " << n << " : " << n*sizeof(T) << " (" << reinterpret_cast<unsigned long long>(p) << ")" << endl;
mw_allocator_space -= n*sizeof(T);
std::allocator<T>::deallocate(p, n);
}
mw_allocator() throw(): std::allocator<T>() { cout << " Hello allocator!" << endl; }
mw_allocator(const mw_allocator &a) throw(): std::allocator<T>(a) { }
template <class U>
mw_allocator(const mw_allocator<U> &a) throw(): std::allocator<T>(a) { }
~mw_allocator() throw() { }
};
}
typedef std::basic_string<char, std::char_traits<char>, mw_allocator_namespace::mw_allocator<char> > my_string;
int main() {
string s1("Hello World1");
my_string ms1;
#if 0
// This doesn't work
ms1 = s1;
#else
// This does...
ms1 = s1.c_str();
#endif
cout << "ms1: " << ms1 << endl;
return 0;
}