在C++中是否可能声明变量而不实例化它?我想要做类似这样的事情:
Animal a;
if( happyDay() )
a( "puppies" ); //constructor call
else
a( "toads" );
基本上,我只是想在条件语句外声明一个变量 a
,以便它获得正确的作用域。
有没有不使用指针并在堆上分配a
的方法?也许可以使用引用实现巧妙的解决方案吗?
在C++中是否可能声明变量而不实例化它?我想要做类似这样的事情:
Animal a;
if( happyDay() )
a( "puppies" ); //constructor call
else
a( "toads" );
基本上,我只是想在条件语句外声明一个变量 a
,以便它获得正确的作用域。
有没有不使用指针并在堆上分配a
的方法?也许可以使用引用实现巧妙的解决方案吗?
这里不能使用引用,因为一旦超出作用域,引用将指向一个已被删除的对象。
实际上,你有两个选择:
1- 使用指针:
Animal* a;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
// ...
delete a;
或者使用智能指针。#include <memory>
std::unique_ptr<Animal> a;
if( happyDay() )
a = std::make_unique<Animal>( "puppies" );
else
a = std::make_unique<Animal>( "toads" );
2- 为 Animal
添加一个初始化方法:
class Animal
{
public:
Animal(){}
void Init( const std::string& type )
{
m_type = type;
}
private:
std:string m_type;
};
Animal a;
if( happyDay() )
a.Init( "puppies" );
else
a.Init( "toads" );
我个人会选择选项2。
unique_ptr
。 - Chronial你不能在不调用构造函数的情况下声明一个变量。但是,在你的例子中,你可以这样做:
Animal a(happyDay() ? "puppies" : "toads");
在C++中,由于对象是在使用默认构造函数定义时构造的,所以您无法直接这样做。
但是,您可以通过运行带参数的构造函数来开始:
Animal a(getAppropriateString());
或者你可以使用类似于 ?:运算符
的东西来确定正确的字符串。(更新:@Greg 给出了语法。请查看该答案)我更倾向于Greg的答案,但你也可以这样做:
char *AnimalType;
if( happyDay() )
AnimalType = "puppies";
else
AnimalType = "toads";
Animal a(AnimalType);
我提出这个建议是因为我曾经工作过的某些地方禁止使用条件运算符。(叹气!)此外,这种方法可以非常容易地扩展到两个以上的选择。
如果您想避免垃圾回收,可以使用智能指针。
auto_ptr<Animal> p_a;
if ( happyDay() )
p_a.reset(new Animal( "puppies" ) );
else
p_a.reset(new Animal( "toads" ) );
// do stuff with p_a-> whatever. When p_a goes out of scope, it's deleted.
如果你仍然希望使用.语法而不是->,那么你可以在上面的代码之后这样做:
Animal& a = *p_a;
// do stuff with a. whatever
void body(Animal & a) {
...
}
if( happyDay() ) {
Animal a("puppies");
body( a );
} else {
Animal a("toad");
body( a );
}
滥用placement new:
struct AnimalDtor {
void *m_a;
AnimalDtor(void *a) : m_a(a) {}
~AnimalDtor() { static_cast<Animal*>(m_a)->~Animal(); }
};
char animal_buf[sizeof(Animal)]; // still stack allocated
if( happyDay() )
new (animal_buf) Animal("puppies");
else
new (animal_buf) Animal("toad");
AnimalDtor dtor(animal_buf); // make sure the dtor still gets called
Animal & a(*static_cast<Animal*>(static_cast<void*>(animal_buf));
... // carry on
std::optional
。在这种情况下,代码如下:#include <optional>
std::optional<Animal> a;
if (happyDay()) {
a.emplace("puppies");
} else {
a.emplace("toads");
}
a
的默认构造函数。 - Quantum7optional
确实有一个微小的开销来存储布尔值(在我的系统上为8字节)并初始化自身。 - Quantum7Animal a*;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
new
时,变量存储在堆中,应稍后删除。 - nathanfranke有一种方法可以在不使用指针/堆内存的情况下完成这个操作,但这种语法有点晦涩难懂。以下是使用std::string的示例。除非您确实需要性能,否则我不建议这样做。
uint8_t object[sizeof(std::string)];
int main() {
if(true)
new(&object) std::string("Your arguments");
else
new(&object) std::string("Your other arguments");
(*(std::string*)(&object)).append("");
std::cout << (*(std::string*)(&object));
return 0;
}
(*(std::string*)(&object))
class Ball {
private:
// This is initialized, but not as needed
sf::Sprite ball;
public:
Ball() {
texture.loadFromFile("ball.png");
// This is a local object, not the same as the class member.
sf::Sprite ball2(texture);
// move it
this->ball=std::move(ball2);
}
...
std::move
在这里确实有潜力使用,但是这段代码并没有展示如何解决问题中的双重初始化。您能否重新编写您的答案以更紧密地跟随我的问题(例如实现一个Animal(char *)
构造函数)?您还应该声明这需要C++11。 - Quantum7