As I'm not a developer I'm sure this is a keyword research problem more than anything else.
Considering
class A
{
public:
B* myBpointer;
[...]
}
class B
{
[...]
}
and a simple snippet:
int main(int argc, char** argv)
{
A myA;
while(1)
{
if(myA.myBpointer)delete myA.myBpointer;
myA.myBpointer = new B;
[...]
}
return 0;
}
Is there in c++ a better way to declare myBpointer to avoid to check if the pointer is null before actually assigning it if not or deleting it then assigning it before?
If you use a smart pointer like std::unique_ptr or std::shared_ptr, then the memory managed by it will be kept alive or deleted as you'd expect.
If you assign to a unique_ptr, whatever memory it was managing would be deleted before assuming responsibility of the new memory.
Related
I implement a wrapper around the Google V8 engine. I wrote a class:
class Es
{
public:
Es();
~Es();
int Init(const char* exec_path);
int CreateContext(uint& id);
int RemoveContext(const uint id);
protected:
Global<Context> global_context;
std::map<uint, Persistent<Context>*> contexts;
Isolate* isolate = nullptr;
private:
uint next_id = 1;
};
I want to create Contexts, hold them in the contexts var, and remove them oneday. So, I init the V8 engine:
int Es::Init(const char* exec_path)
{
v8::V8::InitializeICUDefaultLocation(exec_path);
v8::V8::InitializeExternalStartupData(exec_path);
std::unique_ptr<Platform> platform = platform::NewDefaultPlatform();
V8::InitializePlatform(platform.get());
V8::Initialize();
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = ArrayBuffer::Allocator::NewDefaultAllocator();
isolate = Isolate::New(create_params);
if (!isolate)
return InitError;
return Success;
}
And after that I want to create a context, using int Es::CreateContext(uint& id). Its called after Init.
int EasyProspect::CreateContext(uint& id)
{
if (!isolate)
return NotInitializedError;
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
Local<Context> local_context = Context::New(isolate);
Persistent<Context> context(isolate, local_context);
contexts.emplace(id, &context);
return Success;
}
But I can't do that, the code crashes on Context::New(isolate). Why? isolate is not null, I enter the local scope...
Your best bet is to compile in Debug mode and run in a debugger. Then it should be easy to tell what's causing the crash.
(At the very least, you should post a complete reproducible example, including specifying the V8 version you're working with, how that's built/configured, and how you're compiling your code.)
If I had to guess: the Platform and the ArrayBuffer::Allocator need to stay alive for as long as you want to use the V8 instance, but in your code they are both destroyed at the end of Es::Init. Since Es is a wrapper class, you can easily add fields there to keep them around.
I’m trying to use static_assert to force something to fail. If you try to instantiate a specific templated function in a specific way I want to generate a complier error. I could make it work, but it was really ugly. Is there an easier way to do this?
This was my first attempt. This did not work at all. It always generates an error, even if no one tries to use this function.
template< class T >
void marshal(std::string name, T *value)
{
static_assert(false, "You cannot marshal a pointer.");
}
Here’s my second attempt. It actually works. If you don’t call this, you get no error. If you do call this, you get a very readable error message that points to this line and points to the code that tried to instantiate it.
template< class T >
void marshal(std::string name, T *value)
{
static_assert(std::is_pod<T>::value && !std::is_pod<T>::value, "You cannot marshal a pointer.");
}
The problem is that this code is ugly at best. It looks like a hack. I’m afraid the next time I change the optimization level, upgrade my compiler, sneeze, etc, the compiler will realize that this second case is the same as the first, and they will both stop working.
Is there a better way to do what I’m trying to do?
Here’s some context. I want to have several different versions of marshal() which work for different input types. I want one version that uses a template as the default case. I want another one that specifically disallows any pointers except char *.
void marshal(std::string name, std::string)
{
std::cout<<name<<" is a std::string type."<<std::endl;
}
void marshal(std::string name, char *string)
{
marshal(name, std::string(string));
}
void marshal(std::string name, char const *string)
{
marshal(name, std::string(string));
}
template< class T >
void marshal(std::string name, T value)
{
typedef typename std::enable_if<std::is_pod<T>::value>::type OnlyAllowPOD;
std::cout<<name<<" is a POD type."<<std::endl;
}
template< class T >
void marshal(std::string name, T *value)
{
static_assert(false, "You cannot marshal a pointer.");
}
int main (int argc, char **argv)
{
marshal(“should be pod”, argc);
marshal(“should fail to compile”, argv);
marshal(“should fail to compile”, &argc);
marshal(“should be std::string”, argv[0]);
}
There is no way to do this. You might be able to make it work on your compiler, but the resulting program is ill formed no diagnostic required.
Use =delete.
template< class T >
void marshal(std::string name, T *value) = delete;
What you are trying to do is doomed to be ill-formed (even your workaround can fail) according to [temp.res]/8 (emphasis mine):
Knowing which names are type names allows the syntax of every template
to be checked. The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the
template is not instantiated, or (...)
Relying on a contradiction is not the best indeed, but there's a simpler way:
template <class...>
struct False : std::bool_constant<false> { };
template <class T>
void bang() {
static_assert(False<T>{}, "bang!");
}
Why does this not fall under the "no valid specialization" case?
Well, because you can actually make a valid specialization, with that second half of the code:
template <>
struct False<int> : std::bool_constant<true> { };
int main() {
bang<int>(); // No "bang"!
}
Of course, no one is actually going to specialize False to break your assertions in real code, but it is possible :)
I don't understand why you have template< class T > void marshal(std::string name, T *value) in the first place. This should just be a static_assert in the primary template.
That is, you should change the definition of your primary template to
template< class T >
void marshal(std::string name, T value)
{
static_assert(std::is_pod<T>::value);
static_assert(!std::is_pointer<T>::value);
std::cout<<name<<" is a POD type."<<std::endl;
}
I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this. But what about this situation?
class config;
class cfg_item final
{
private:
friend class config;
cfg_item(std::weak_ptr<config> owner) : owner(owner) { }
std::weak_ptr<config> owner;
}
class config final : private std::enable_shared_from_this<config>
{
public:
config()
{
items.emplace(std::make_shared<cfg_item>(weak_from_this())); // Will crash!
}
private:
std::vector<std::shared_ptr<cfg_item>> items;
}
int main(int argc, char * argv[])
{
std::shared_ptr<config> cfg = std::make_shared<config>();
}
I KNOW WHY IT CRASHES. The std::shared_ptr in the main is not yet initialized with shared pointer to config instance, so constructor does not know how to make weak_from_this and just raises std::bad_weak_ptr exception because there are no valid std::shared_ptr pointing to this at constructor's call time.
The question is: how can I avoided the whole thing? I believe the only way I see would be to add separate initialization method, which is evil as I've already mentioned...
As note about real code: the constructors loads cfg_item from external source. It is assumed that all cfg_items are available for the entire lifetime of config. The weak pointers back to config are mandatory, as cfg_item must push all changes done to it back to config to save to external source
If you look at the answers to this question, there are strong arguments why an external initialization function is necessary. However, you rightfully write
I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this.
it's possible to reduce this problem. Say you have a class foo, with the protocol that each time a foo object is constructed, foo::init() needs to be called. Obviously, this is a brittle class (client code will eventually omit calls to init()).
So, one way is to make the (non-copy / non-move) constructors of foo private, and create a variadic static factory method that creates objects, then calls init():
#include <utility>
class foo {
private:
foo() {}
foo(int) {}
void init() {}
public:
template<typename ...Args>
static foo create(Args &&...args) {
foo f{std::forward<Args>(args)...};
f.init();
return f;
}
};
In the following code
template<typename ...Args>
static foo create(Args &&...args) {
foo f{std::forward<Args>(args)...};
f.init();
return f;
}
note that this single method can be used for all constructors, regardless of their signature. Furthermore, since it is static, it is external to the constructor, and doesn't have the problems in your question.
You can use it as follows:
int main() {
auto f0 = foo::create();
auto f1 = foo::create(2);
// Next line doesn't compile if uncommented
// foo f2;
}
Note that it's impossible to create an object without this method, and the interface doesn't even contain init.
I am trying to replace Poco::AutoPtr with some alternative in boost. Here is what I have discovered so far:
What I have: below classess are being used with Poco::AutoPtr. They need to implement reference counted method with implementing duplicate() and release() methods.
I am using above referece_counted.h and Poco::AutoPtr in a complex class hierarchy with multiple inheritance and c++ diamond problems.
A simplified version of classes would look something like this
class A : virtual public ReferenceCounted
{
...
}
class B : public A
{
...
}
class C : public A
{
...
}
class D : public A, B
{
...
}
and the list goes on for few more level deep. I know that this needs to be refactored with a simplified hierarchy but I wanna remove Poco::AutoPtr first with proper replacement in boost:
What I have found so far:
I have found that boost::intrusive_ptr is the closest smart pointer that can be a good replacement of Poco::AutoPtr.
I am however not able to implement the proper solution with this because the intrusive_ptr requires intrusive_ptr_add_ref and intrusive_ptr_release methods created specifically for each class with which I need to use the pointer. I tried using templates but still not having proper solution at hand.
Also one more issue is that I need to typecast from base to derived class many times.
is intrusive_ptr is the correct smart pointer for this usage ? and if yes.. can anybody give me suggestion regarding how to use the same ?
I am however not able to implement the proper solution with this
because the intrusive_ptr requires intrusive_ptr_add_ref and
intrusive_ptr_release methods created specifically for each class with
which I need to use the pointer.
No-no. It is should not be hard. As Boost documentation says:
On compilers that support argument-dependent lookup,
intrusive_ptr_add_ref and intrusive_ptr_release should be defined in
the namespace that corresponds to their parameter; otherwise, the
definitions need to go in namespace boost.
Try this: main.cpp (built ok with "g++ main.cpp -o main -lboost_system")
#include <boost/intrusive_ptr.hpp>
class MyObject
{
public:
void duplicate(){
// ...
}
void release(){
// ...
}
};
namespace boost {
template <class T>
void intrusive_ptr_add_ref( T * po ) {
po->duplicate(); // your internal realization
}
template <class T>
void intrusive_ptr_release( T * po ) {
po->release();
}
}
int main(int argc, char **argv)
{
// ...
boost::intrusive_ptr<MyObject> ptr( new MyObject );
boost::intrusive_ptr<MyObject> ptr2 = ptr; // should work
}
In N3257 I found an example using initializing members without a constructor, which is fine. I guess that is possible, because it is a POD.
template<typename T>
struct adaptor {
NonStdContainer<T>* ptr; // <- data member
T* begin() { return ptr->getFirst(); }
T* end() { return ptr->getLast() + 1; }
};
void f(NonStdContainer<int>& c) {
for (auto i : adaptor<int>{&c}) // <- init
{ /* ... */ }
}
When I played around with this example I replaced the * with a &, because I don't like raw pointers:
template<typename T>
struct adaptor {
NonStdContainer<T>& ptr; // <- data member, now REF
T* begin() { return ptr->getFirst(); }
T* end() { return ptr->getLast() + 1; }
};
void f(NonStdContainer<int>& c) {
for (auto i : adaptor<int>{c}) // <- init
{ /* ... */ }
}
This was fine and compiled without warning with GCC-4.7.0.
Then I got curious about the initialization of PODs and what might have changed with C++0x.
There I found Bjarnes FAQ. He says there that PODs may contain pointers, but no references.
Ops, now I wonder:
Do I have non-POD-object here, which the compiler can initialize without a constructor anyway and I just miss which mechanisms are used here?
or Is the GCC-4.7.0 behaving non-std by letting me initializing the ref this way?
or has there been a change in the std since Bjarnes FAQ that also allows references in PODs?
Update: I found aggregates in the current std (8.5.1 Aggregates [dcl.init.aggr]), but references are not mentioned there, so I am not sure how they relate to this
Quoting the standard [dcl.init.aggr]:
An aggregate is an array or a class (Clause 9) with no user-provided
constructors (12.1), no brace-or-equal- initializers for non-static
data members (9.2), no private or protected non-static data members
(Clause 11), no base classes (Clause 10), and no virtual functions
(10.3).
When an aggregate is initialized by an initializer list, as specified
in 8.5.4, the elements of the initializer list are taken as
initializers for the members of the aggregate, in increasing subscript
or member order. Each member is copy-initialized from the corresponding initializer-clause...
That means you have an aggregate here, aggregates can be initialized how you do it. PODs have nothing to do with it, they are really meant for communication with eg. C.
Copy-initialization of a reference with a variable is certainly legal, because that just means
T& ref = c;
Do I have non-POD-object here, which the compiler can initialize without a constructor anyway and I just miss which mechanisms are used here?
Yes, the object is non-POD.
Is the GCC-4.7.0 behaving non-std by letting me initializing the ref this way?
No.