我创建了一个简单的测试用例,展示了我在一个更大的代码库中注意到的奇怪行为.这个测试用例如下.我依靠STL Map的"[]"运算符来创建指向这种结构的映射中的结构的指针.在下面的测试用例中,线...
TestStruct *thisTestStruct = &testStructMap["test"];
Run Code Online (Sandbox Code Playgroud)
...给我指针(并在地图中创建一个新条目).我注意到的奇怪之处在于,这一行不仅会导致地图中的新条目被创建(因为"[]"运算符),但由于某种原因,它会导致结构体的析构函数被多次调用两次.我显然错过了一些东西 - 非常感谢任何帮助!谢谢!
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct TestStruct;
int main (int argc, char * const argv[]) {
map<string, TestStruct> testStructMap;
std::cout << "Marker One\n";
//why does this line cause "~TestStruct()" to be invoked twice?
TestStruct *thisTestStruct = &testStructMap["test"];
std::cout << "Marker Two\n";
return 0;
}
struct TestStruct{
TestStruct(){
std::cout << "TestStruct Constructor!\n";
}
~TestStruct(){
std::cout << "TestStruct Destructor!\n";
}
};
Run Code Online (Sandbox Code Playgroud)
上面的代码输出以下内容......
/*
Marker One
TestStruct Constructor! //makes sense …Run Code Online (Sandbox Code Playgroud) 我刚刚意识到这个程序编译并运行(gcc版本4.4.5/Ubuntu):
#include <iostream>
using namespace std;
class Test
{
public:
// copyconstructor
Test(const Test& other);
};
Test::Test(const Test& other)
{
if (this == &other)
cout << "copying myself" << endl;
else
cout << "copying something else" << endl;
}
int main(int argv, char** argc)
{
Test a(a); // compiles, runs and prints "copying myself"
Test *b = new Test(*b); // compiles, runs and prints "copying something else"
}
Run Code Online (Sandbox Code Playgroud)
我想知道为什么这个甚至可以编译.我假设(就像在Java中)参数在调用方法/构造函数之前被评估,所以我怀疑这个案例必须由语言规范中的一些"特殊情况"涵盖?
问题:
编辑1:我刚刚意识到我甚至可以写作 int i = i;
编辑2:即使有-Wall …
我们知道,如果声明了任何构造函数(包含复制构造函数),则不会隐式创建默认构造函数(不带参数的构造函数).使用默认复制构造函数(执行对象的浅层复制的构造函数)会发生同样的情况吗?此外,析构函数的存在是否会对此产生影响?
我正在阅读直接初始化和复制初始化(§8.5/ 12)之间的区别:
T x(a); //direct-initialization
T y = a; //copy-initialization
Run Code Online (Sandbox Code Playgroud)
我从阅读有关复制初始化的内容中了解到,它需要可访问和非显式的复制构造函数,否则程序将无法编译.我通过编写以下代码验证了它:
struct A
{
int i;
A(int i) : i(i) { std::cout << " A(int i)" << std::endl; }
private:
A(const A &a) { std::cout << " A(const A &)" << std::endl; }
};
int main() {
A a = 10; //error - copy-ctor is private!
}
Run Code Online (Sandbox Code Playgroud)
GCC给出了一个错误(ideone)说:
prog.cpp:8:错误:'A :: A(const A&)'是私有的
到目前为止,一切都很好,重申Herb Sutter所说的,
复制初始化意味着在必要时首次调用用户定义的转换后,使用复制构造函数初始化对象,并且等效于"T t = u;"形式:
之后,我通过评论private …
在通用编程和STL(中文版)一书中,它说:
X x = X()将调用复制构造函数.
这对我来说似乎有点奇怪.我写了一个像这样的测试程序
#include <iostream>
class Test {
public:
Test() {
std::cout << "This is ctor\n";
}
Test(const Test&) {
std::cout << "This is copy-ctor\n";
}
};
int main(int argc, char** argv)
{
Test t = Test();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是"This is ctor".好的,现在我很困惑,这是对的吗?
实例化模板类的特殊成员函数(特别是复制/移动构造函数和复制/移动赋值运算符)是什么时候?一旦类本身被实例化,或者仅在需要它们时?
这出现在以下情况:
template <class T, class U>
struct pair
{
T first;
U second;
pair() : first(), second() {}
pair(const pair&) = default;
};
struct S
{
S() {}
S(const S&) = delete;
S(S&&) = default;
};
int main()
{
pair<int, S> p;
}
Run Code Online (Sandbox Code Playgroud)
Clang拒绝编译此代码,但有以下错误:
test.cpp:9:5: error: the parameter for this explicitly-defaulted copy constructor is const, but a member or base requires it to be
non-const
pair(const pair&) = default;
^
test.cpp:21:18: note: in instantiation of template class 'pair<int, S>' …Run Code Online (Sandbox Code Playgroud) 给定X下面的类(除了明确定义的特殊成员函数与此实验无关):
struct X
{
X() { }
X(int) { }
X(X const&) { std::cout << "X(X const&)" << std::endl; }
X(X&&) { std::cout << "X(X&&)" << std::endl; }
};
Run Code Online (Sandbox Code Playgroud)
以下程序创建一个类型对象的向量X并调整其大小,以便超出其容量并强制重新分配:
#include <iostream>
#include <vector>
int main()
{
std::vector<X> v(5);
v.resize(v.capacity() + 1);
}
Run Code Online (Sandbox Code Playgroud)
由于class X提供了一个移动构造函数,我希望在重新分配之后将向量的先前内容移动到新存储中.相当令人惊讶的是,情况似乎并非如此,我得到的输出是:
X(X const&)
X(X const&)
X(X const&)
X(X const&)
X(X const&)
Run Code Online (Sandbox Code Playgroud)
为什么?
在下面的示例中,GCC >= 4.7实例化模板构造函数(您可以通过读取错误消息来观察),尽管只需要隐式生成的复制构造函数.
#include <type_traits>
// 'ambiguous' is ambiguous for 'ambiguous<int, int>'
template<typename A, typename B>
struct ambiguous : std::false_type {};
template<typename T>
struct ambiguous<int, T> : std::true_type {};
template<typename T>
struct ambiguous<T, int> : std::true_type {};
// quantity
template<typename Type>
class quantity
{
public:
quantity() = default;
// Copy-constructor is implicitly created
// Template constructor
template<
typename T,
typename = typename std::enable_if<ambiguous<Type, T>::value>::type
>
quantity(quantity<T>) {}
template<
typename T,
typename = typename std::enable_if<ambiguous<Type, T>::value>::type
>
void set(quantity<T>) …Run Code Online (Sandbox Code Playgroud) 在下面的代码中,"情境1" 在所有测试的编译器上按预期工作,但"情况2"似乎根据所使用的编译器而表现不同.
作为示例,MSVC使sit1和sit2产生相同的结果,但是当使用gcc/clang和libstdc ++时,修改发生在原始字符串和它的副本(有点像COW字符串),即使我正在使用C +构建+11开关.
#include <iostream>
#include <string>
int main() {
// situation 1
{
std::string x0 = "12345678";
std::string x1 = x0;
char* ptr = &x0[0] + 3;
(*ptr) = ' ';
std::cout << "1. x0: " << x0 << "\n";
std::cout << "1. x1: " << x1 << "\n";
if ((&x0[0]) == x0.data()) std::cout << "1. ptrs are equal\n";
}
// situation 2
{
std::string x0 = "12345678";
std::string x1 = x0; …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
#include <memory>
#include <vector>
class A
{
private:
std::vector<std::unique_ptr<int>> _vals;
};
int main()
{
A a;
//A a2(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器A没有问题地编译它,除非我取消注释A a2(a);它抱怨复制构造函数std::unique_ptr被删除的那一行,因此我不能复制构造A.然而,即使我将该行留下注释,编译器B也会提出投诉.也就是说,当我实际尝试使用它时,编译器A只生成一个隐式定义的复制构造函数,而编译器B则无条件地这样做.哪一个是正确的?请注意,如果我使用std::unique_ptr<int> _vals;而不是std::vector<std::unique_ptr<int>> _vals;两个编译器正确地隐式删除复制构造函数和赋值运算符(std::unique_ptr具有显式删除的复制构造函数,而std::vector不是).
(注:获取代码编译器B到编译是很容易的 - 只要明确地删除拷贝构造函数和赋值运算符,并且它能够正常工作这不是问题的问题,它是要了解正确的行为.)
c++ copy-constructor assignment-operator language-lawyer c++11
c++ ×10
copy-constructor ×10
c++11 ×4
constructor ×2
clang ×1
gcc ×1
stl ×1
string ×1
templates ×1